diff --git a/src/discord/Frontend.hpp b/src/discord/Frontend.hpp index 9d6edbd..a993a85 100644 --- a/src/discord/Frontend.hpp +++ b/src/discord/Frontend.hpp @@ -98,6 +98,10 @@ class Frontend virtual std::string GetFormatTimeShortText() = 0; virtual std::string GetFormatTimeShorterText() = 0; + virtual void HideWindow() = 0; + virtual void RestoreWindow() = 0; + virtual void MaximizeWindow() = 0; + // Debugging #ifdef USE_DEBUG_PRINTS virtual void DebugPrint(const char* fmt, va_list vl) = 0; diff --git a/src/discord/LocalSettings.cpp b/src/discord/LocalSettings.cpp index c7d81b5..0371acc 100644 --- a/src/discord/LocalSettings.cpp +++ b/src/discord/LocalSettings.cpp @@ -71,6 +71,18 @@ bool LocalSettings::Load() if (j.contains("StartMaximized")) m_bStartMaximized = j["StartMaximized"]; + if (j.contains("OpenOnStartup")) + m_bOpenOnStartup = j["OpenOnStartup"]; + + if (j.contains("StartMinimized")) + m_bStartMinimized = j["StartMinimized"]; + + if (j.contains("MinimizeToNotif")) + m_bMinimizeToNotif = j["MinimizeToNotif"]; + + if (j.contains("Maximized")) + m_bMaximized = j["Maximized"]; + if (j.contains("EnableTLSVerification")) m_bEnableTLSVerification = j["EnableTLSVerification"]; @@ -134,7 +146,6 @@ bool LocalSettings::Load() if (j.contains("AddExtraHeaders")) m_bAddExtraHeaders = j["AddExtraHeaders"]; - return true; } @@ -153,6 +164,10 @@ bool LocalSettings::Save() j["ReplyMentionDefault"] = m_bReplyMentionDefault; j["StartMaximized"] = m_bStartMaximized; j["SaveWindowSize"] = m_bSaveWindowSize; + j["OpenOnStartup"] = m_bOpenOnStartup; + j["StartMinimized"] = m_bStartMinimized; + j["MinimizeToNotif"] = m_bMinimizeToNotif; + j["Maximized"] = m_bMaximized; j["CheckUpdates"] = m_bCheckUpdates; j["EnableTLSVerification"] = m_bEnableTLSVerification; j["DisableFormatting"] = m_bDisableFormatting; diff --git a/src/discord/LocalSettings.hpp b/src/discord/LocalSettings.hpp index d94e0ca..61647ea 100644 --- a/src/discord/LocalSettings.hpp +++ b/src/discord/LocalSettings.hpp @@ -74,6 +74,30 @@ class LocalSettings bool GetStartMaximized() const { return m_bStartMaximized; } + void SetOpenOnStartup(bool b) { + m_bOpenOnStartup = b; + } + bool GetOpenOnStartup() const { + return m_bOpenOnStartup; + } + void SetStartMinimized(bool b) { + m_bStartMinimized = b; + } + bool GetStartMinimized() const { + return m_bStartMinimized; + } + void SetMinimizeToNotif(bool b) { + m_bMinimizeToNotif = b; + } + bool GetMinimizeToNotif() const { + return m_bMinimizeToNotif; + } + void SetMaximized(bool b) { + m_bMaximized = b; + } + bool GetMaximized() const { + return m_bMaximized; + } bool IsFirstStart() const { return m_bIsFirstStart; } @@ -193,6 +217,10 @@ class LocalSettings bool m_bReplyMentionDefault = true; bool m_bSaveWindowSize = false; bool m_bStartMaximized = false; + bool m_bOpenOnStartup = false; + bool m_bStartMinimized = false; + bool m_bMinimizeToNotif = true; + bool m_bMaximized = false; bool m_bIsFirstStart = false; bool m_bCheckUpdates = false; bool m_bAskToCheckUpdates = true; diff --git a/src/resource.h b/src/resource.h index 21e88de..6fc90fe 100644 --- a/src/resource.h +++ b/src/resource.h @@ -98,6 +98,7 @@ #define IDI_SCROLL 98 #define IDI_NOTIFICATION 99 #define IDI_NOTIFICATION_2K 100 +#define IDR_NOTIFICATION_CONTEXT 101 #define IDB_TARGET 200 #define IDB_CHANNEL 201 #define IDB_CATEGORY 202 @@ -475,6 +476,8 @@ #define IDM_BLOCK 1065 #define IDM_COPYID 1066 #define ID_ACTIONS_QUICKSWITCHER 1067 +#define ID_NOTIFICATION_SHOW 1068 +#define ID_NOTIFICATION_EXIT 1069 #define IDR_MAIN_ACCELS 1201 #define IDA_SEARCH 1301 #define IDA_QUICKSWITCHER 1302 @@ -484,8 +487,8 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 101 -#define _APS_NEXT_COMMAND_VALUE 1069 +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 1079 #define _APS_NEXT_CONTROL_VALUE 904 #define _APS_NEXT_SYMED_VALUE 40000 #endif diff --git a/src/resource.rc b/src/resource.rc index a09b95e..e685c17 100644 --- a/src/resource.rc +++ b/src/resource.rc @@ -202,6 +202,24 @@ BEGIN END END +IDR_NOTIFICATION_CONTEXT MENU +BEGIN + POPUP "Notification" + BEGIN + MENUITEM "Show", ID_NOTIFICATION_SHOW + POPUP "Status" + BEGIN + MENUITEM "Online", ID_ONLINESTATUSPLACEHOLDER_ONLINE, CHECKED + MENUITEM SEPARATOR + MENUITEM "Idle", ID_ONLINESTATUSPLACEHOLDER_IDLE + MENUITEM "Do not disturb", ID_ONLINESTATUSPLACEHOLDER_DONOTDISTURB + MENUITEM "Invisible", ID_ONLINESTATUSPLACEHOLDER_INVISIBLE + END + MENUITEM SEPARATOR + MENUITEM "Exit", ID_NOTIFICATION_EXIT + END +END + ///////////////////////////////////////////////////////////////////////////// // @@ -683,11 +701,11 @@ BEGIN CONTROL "Save window size",IDC_SAVE_WINDOW_SIZE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,18,236,10 CONTROL "Start maximized",IDC_START_MAXIMIZED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,32,236,10 CONTROL "Open Discord Messenger when your computer starts",IDC_OPEN_ON_STARTUP, - "Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,12,46,242,10 + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,46,242,10 CONTROL "Open minimized to notification area",IDC_START_MINIMIZED, "Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,32,60,222,10 CONTROL "Minimize to notification area when clicking the close button",IDC_MINIMIZE_TO_NOTIF, - "Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,12,74,242,10 + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,74,242,10 END diff --git a/src/windows/Frontend_Win32.cpp b/src/windows/Frontend_Win32.cpp index a1ab383..9aaddba 100644 --- a/src/windows/Frontend_Win32.cpp +++ b/src/windows/Frontend_Win32.cpp @@ -399,6 +399,21 @@ void Frontend_Win32::RequestQuit() ::WantQuit(); } +void Frontend_Win32::HideWindow() +{ + ShowWindow(g_Hwnd, SW_HIDE); +} + +void Frontend_Win32::RestoreWindow() +{ + ShowWindow(g_Hwnd, SW_RESTORE); +} + +void Frontend_Win32::MaximizeWindow() +{ + ShowWindow(g_Hwnd, SW_MAXIMIZE); +} + bool Frontend_Win32::IsWindowMinimized() { return IsIconic(g_Hwnd); diff --git a/src/windows/Frontend_Win32.hpp b/src/windows/Frontend_Win32.hpp index 0f3ebd9..e991a17 100644 --- a/src/windows/Frontend_Win32.hpp +++ b/src/windows/Frontend_Win32.hpp @@ -59,6 +59,9 @@ class Frontend_Win32 : public Frontend void RegisterAttachment(Snowflake sf, const std::string& avatarlnk) override; void RegisterChannelIcon(Snowflake sf, const std::string& avatarlnk) override; void RequestQuit() override; + void HideWindow() override; + void RestoreWindow() override; + void MaximizeWindow() override; bool IsWindowMinimized() override; std::string GetDirectMessagesText() override; std::string GetPleaseWaitText() override; diff --git a/src/windows/InstanceMutex.cpp b/src/windows/InstanceMutex.cpp new file mode 100644 index 0000000..a963ee6 --- /dev/null +++ b/src/windows/InstanceMutex.cpp @@ -0,0 +1,31 @@ +#include "InstanceMutex.hpp" + +void InstanceMutex::Close() +{ + if (m_handle) + { + CloseHandle(m_handle); + m_handle = NULL; + } +} + +HRESULT InstanceMutex::Init() +{ +#ifdef DISABLE_SINGLE_INSTANCE + return 0; +#else + + m_handle = CreateMutex(NULL, TRUE, TEXT("DiscordMessenger")); + + const DWORD error = GetLastError(); + if (error == ERROR_ALREADY_EXISTS) + Close(); + + return error; +#endif +} + +InstanceMutex::~InstanceMutex() +{ + Close(); +} \ No newline at end of file diff --git a/src/windows/InstanceMutex.hpp b/src/windows/InstanceMutex.hpp new file mode 100644 index 0000000..fa004fc --- /dev/null +++ b/src/windows/InstanceMutex.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include + +class InstanceMutex +{ +private: + HANDLE m_handle = NULL; + + void Close(); + +public: + HRESULT Init(); + ~InstanceMutex(); +}; \ No newline at end of file diff --git a/src/windows/LoadingMessage.cpp b/src/windows/LoadingMessage.cpp index 4938f35..99091b2 100644 --- a/src/windows/LoadingMessage.cpp +++ b/src/windows/LoadingMessage.cpp @@ -46,7 +46,7 @@ void LoadingMessage::Show() if (!m_hwnd) { CreateWnd(); ShowWindow(m_hwnd, SW_SHOWNORMAL); - SetFocus(m_hwnd); + SetActiveWindow(m_hwnd); } } diff --git a/src/windows/Main.cpp b/src/windows/Main.cpp index 3e5628c..980a821 100644 --- a/src/windows/Main.cpp +++ b/src/windows/Main.cpp @@ -25,6 +25,7 @@ #include "ProgressDialog.hpp" #include "AutoComplete.hpp" #include "ShellNotification.hpp" +#include "InstanceMutex.hpp" #include "../discord/LocalSettings.hpp" #include "../discord/WebsocketClient.hpp" #include "../discord/UpdateChecker.hpp" @@ -415,6 +416,14 @@ int OnSSLError(const std::string& url) return MessageBox(g_Hwnd, buffer, TmGetTString(IDS_SSL_ERROR_TITLE), MB_ABORTRETRYIGNORE | MB_ICONWARNING); } +void CloseCleanup(HWND hWnd) +{ + KillImageViewer(); + ProfilePopout::Dismiss(); + AutoComplete::DismissAutoCompleteWindowsIfNeeded(hWnd); + g_pLoadingMessage->Hide(); +} + BOOL HandleCommand(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (LOWORD(wParam)) @@ -438,7 +447,7 @@ BOOL HandleCommand(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) } case ID_FILE_EXIT: { - SendMessage(hWnd, WM_CLOSE, 0, 0); + SendMessage(hWnd, WM_CLOSEBYPASSTRAY, 0, 0); return 0; } case ID_HELP_ABOUTDISCORDMESSENGER: @@ -596,6 +605,12 @@ BOOL HandleCommand(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) if (!isClipboardClosed) CloseClipboard(); break; } + case ID_NOTIFICATION_SHOW: + SendMessage(g_Hwnd, WM_RESTOREAPP, 0, 0); + break; + case ID_NOTIFICATION_EXIT: + SendMessage(g_Hwnd, WM_CLOSEBYPASSTRAY, 0, 0); + break; } return DefWindowProc(hWnd, uMsg, wParam, lParam); @@ -622,6 +637,38 @@ void ResetTryAgainInTime() { g_tryAgainTimerElapse = 500; } +const CHAR g_StartupArg[] = "/startup"; + +bool g_bFromStartup = false; + +void CheckIfItsStartup(const LPSTR pCmdLine) +{ + g_bFromStartup = StrStrA(pCmdLine, g_StartupArg); +} + +void AddOrRemoveAppFromStartup() +{ + HKEY hkey = NULL; + RegCreateKey(HKEY_CURRENT_USER, TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Run"), &hkey); + + LPCTSTR value = TmGetTString(IDS_PROGRAM_NAME); + + if (GetLocalSettings()->GetOpenOnStartup()) + { + TCHAR tPath[MAX_PATH]; + const DWORD length = GetModuleFileName(NULL, tPath, MAX_PATH); + + const std::string sPath = "\"" + MakeStringFromTString(tPath) + "\" " + std::string(g_StartupArg); + const LPTSTR finalPath = ConvertCppStringToTString(sPath); + + RegSetValueEx(hkey, value, 0, REG_SZ, (BYTE *)finalPath, (wcslen(finalPath) + 1) * sizeof(TCHAR)); + } + else + { + RegDeleteValue(hkey, value); + } +} + int g_agerCounter = 0; LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) @@ -743,7 +790,9 @@ LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) g_pMessageList->UpdateAllowDrop(); UpdateMainWindowTitle(hWnd); - SetFocus(g_pMessageEditor->m_edit_hwnd); + + if (IsWindowActive(g_Hwnd)) + SetFocus(g_pMessageEditor->m_edit_hwnd); if (!GetDiscordInstance()->GetCurrentChannel()) { @@ -1093,9 +1142,14 @@ LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) g_tryAgainTimer = 0; } g_pLoadingMessage->Hide(); + + if (g_bFromStartup && GetLocalSettings()->GetStartMinimized()) { + GetFrontend()->HideWindow(); + } break; case WM_CONNECTING: { - g_pLoadingMessage->Show(); + if (!g_bFromStartup || !GetLocalSettings()->GetStartMinimized()) + g_pLoadingMessage->Show(); break; } case WM_LOGINAGAIN: @@ -1116,11 +1170,20 @@ LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) break; } + case WM_CLOSEBYPASSTRAY: + AddOrRemoveAppFromStartup(); + CloseCleanup(hWnd); + DestroyWindow(hWnd); + break; + case WM_CLOSE: - KillImageViewer(); - ProfilePopout::Dismiss(); - AutoComplete::DismissAutoCompleteWindowsIfNeeded(hWnd); - g_pLoadingMessage->Hide(); + CloseCleanup(hWnd); + + if (GetLocalSettings()->GetMinimizeToNotif()) + { + GetFrontend()->HideWindow(); + return 1; + } break; case WM_SIZE: { @@ -1128,6 +1191,7 @@ LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) int height = HIWORD(lParam); // Save the new size GetLocalSettings()->SetWindowSize(UnscaleByDPI(width), UnscaleByDPI(height)); + GetLocalSettings()->SetMaximized(wParam == SIZE_MAXIMIZED); ProfilePopout::Dismiss(); ProperlySizeControls(hWnd); @@ -1430,6 +1494,12 @@ LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) GetShellNotification()->Callback(wParam, lParam); break; } + case WM_RESTOREAPP: + if (GetLocalSettings()->GetMaximized()) + GetFrontend()->MaximizeWindow(); + else + GetFrontend()->RestoreWindow(); + break; } return DefWindowProc(hWnd, uMsg, wParam, lParam); @@ -1563,8 +1633,32 @@ HTTPClient* GetHTTPClient() return g_pHTTPClient; } +InstanceMutex g_instanceMutex; + +static bool ForceSingleInstance(LPCWSTR pClassName) +{ + HRESULT hResult = g_instanceMutex.Init(); + + if (hResult != ERROR_ALREADY_EXISTS) + return true; + + HWND hWnd = FindWindow(pClassName, NULL); + if (hWnd) + { + SendMessage(hWnd, WM_RESTOREAPP, 0, 0); + } + return false; +} + int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLine, int nShowCmd) { + LPCWSTR pClassName = TEXT("DiscordMessengerClass"); + + if (!ForceSingleInstance(pClassName)) + return 0; + + CheckIfItsStartup(pCmdLine); + g_hInstance = hInstance; ri::InitReimplementation(); @@ -1587,14 +1681,14 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLin int wndWidth = 0, wndHeight = 0; bool startMaximized = false; GetLocalSettings()->GetWindowSize(wndWidth, wndHeight); - startMaximized = GetLocalSettings()->GetStartMaximized(); + startMaximized = GetLocalSettings()->GetStartMaximized() || GetLocalSettings()->GetMaximized(); // Initialize the window class. WNDCLASS& wc = g_MainWindowClass; wc.lpfnWndProc = WindowProc; wc.hInstance = hInstance; - wc.lpszClassName = TEXT("DiscordMessengerClass"); + wc.lpszClassName = pClassName; wc.hbrBackground = g_backgroundBrush; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hIcon = g_Icon = LoadIcon(hInstance, MAKEINTRESOURCE(DMIC(IDI_ICON))); @@ -1653,7 +1747,9 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLin TextToSpeech::Initialize(); // Run the message loop. - ShowWindow (g_Hwnd, startMaximized ? SW_SHOWMAXIMIZED : nShowCmd); + + if (!g_bFromStartup || !GetLocalSettings()->GetStartMinimized()) + ShowWindow (g_Hwnd, startMaximized ? SW_SHOWMAXIMIZED : nShowCmd); while (GetMessage(&msg, NULL, 0, 0) > 0) { diff --git a/src/windows/OptionsDialog.cpp b/src/windows/OptionsDialog.cpp index 573a0e7..ea87eeb 100644 --- a/src/windows/OptionsDialog.cpp +++ b/src/windows/OptionsDialog.cpp @@ -242,8 +242,14 @@ void WINAPI OnChildDialogInit(HWND hwndDlg) } case PG_WINDOW: { - CheckDlgButton(hwndDlg, IDC_SAVE_WINDOW_SIZE, GetLocalSettings()->GetSaveWindowSize() ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hwndDlg, IDC_START_MAXIMIZED, GetLocalSettings()->GetStartMaximized() ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_SAVE_WINDOW_SIZE, GetLocalSettings()->GetSaveWindowSize() ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_START_MAXIMIZED, GetLocalSettings()->GetStartMaximized() ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_OPEN_ON_STARTUP, GetLocalSettings()->GetOpenOnStartup() ? BST_CHECKED : BST_UNCHECKED); + + CheckDlgButton(hwndDlg, IDC_START_MINIMIZED, GetLocalSettings()->GetStartMinimized() ? BST_CHECKED : BST_UNCHECKED); + EnableWindow(GetDlgItem(hwndDlg, IDC_START_MINIMIZED), GetLocalSettings()->GetOpenOnStartup()); + + CheckDlgButton(hwndDlg, IDC_MINIMIZE_TO_NOTIF, GetLocalSettings()->GetMinimizeToNotif() ? BST_CHECKED : BST_UNCHECKED); break; } case PG_CONNECTION: @@ -491,6 +497,19 @@ INT_PTR CALLBACK ChildDialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPa case IDC_START_MAXIMIZED: GetLocalSettings()->SetStartMaximized(IsDlgButtonChecked(hWnd, IDC_START_MAXIMIZED)); break; + case IDC_OPEN_ON_STARTUP: + { + const bool checked = IsDlgButtonChecked(hWnd, IDC_OPEN_ON_STARTUP); + GetLocalSettings()->SetOpenOnStartup(checked); + EnableWindow(GetDlgItem(hWnd, IDC_START_MINIMIZED), checked); + break; + } + case IDC_START_MINIMIZED: + GetLocalSettings()->SetStartMinimized(IsDlgButtonChecked(hWnd, IDC_START_MINIMIZED)); + break; + case IDC_MINIMIZE_TO_NOTIF: + GetLocalSettings()->SetMinimizeToNotif(IsDlgButtonChecked(hWnd, IDC_MINIMIZE_TO_NOTIF)); + break; } break; } diff --git a/src/windows/ShellNotification.cpp b/src/windows/ShellNotification.cpp index f1a7a3a..aed7939 100644 --- a/src/windows/ShellNotification.cpp +++ b/src/windows/ShellNotification.cpp @@ -195,6 +195,19 @@ void ShellNotification::OnNotification() m_bAnyNotificationsSinceLastTime = false; } +void ShellNotification::ShowContextMenu() +{ + POINT cursor; + if (!GetCursorPos(&cursor)) { + DbgPrintW("Could not acquire cursor position."); + return; + } + + const HMENU popupMenu = GetSubMenu(LoadMenu(g_hInstance, MAKEINTRESOURCE(IDR_NOTIFICATION_CONTEXT)), 0); + SetForegroundWindow(g_Hwnd); + TrackPopupMenu(popupMenu, TPM_LEFTBUTTON, cursor.x, cursor.y, 0, g_Hwnd, NULL); +} + void ShellNotification::Callback(WPARAM wParam, LPARAM lParam) { switch (LOWORD(lParam)) @@ -224,21 +237,20 @@ void ShellNotification::Callback(WPARAM wParam, LPARAM lParam) { // TODO: Don't know how to know which one we clicked DbgPrintW("Acknowledge Notification"); + + ShowWindow(g_Hwnd, SW_SHOW); + SetActiveWindow(g_Hwnd); + break; } case WM_LBUTTONUP: - case WM_RBUTTONUP: - { - POINT pt; - if (!GetCursorPos(&pt)) { - DbgPrintW("Could not acquire cursor position."); - break; - } + SendMessage(g_Hwnd, WM_RESTOREAPP, 0, 0); + break; - //ShowPopupMenu(pt, LOWORD(wParam) == WM_RBUTTONUP); + case WM_RBUTTONUP: + ShowContextMenu(); break; - } } diff --git a/src/windows/ShellNotification.hpp b/src/windows/ShellNotification.hpp index 0d3e7d5..062cf7d 100644 --- a/src/windows/ShellNotification.hpp +++ b/src/windows/ShellNotification.hpp @@ -22,6 +22,7 @@ class ShellNotification void ShowBalloon(const std::string& titleString, const std::string& contents); void ShowBalloonForOneNotification(Notification* pNotif); void ShowBalloonForNotifications(const std::vector& pNotifs); + void ShowContextMenu(); private: bool m_bInitialized = false; diff --git a/src/windows/WinUtils.cpp b/src/windows/WinUtils.cpp index 0af3f1a..f4f169c 100644 --- a/src/windows/WinUtils.cpp +++ b/src/windows/WinUtils.cpp @@ -133,6 +133,11 @@ void WindowScrollXY(HWND hWnd, int diffLeftRight, int diffUpDown) UpdateWindow(hWnd); } +bool IsWindowActive(HWND hWnd) +{ + return IsWindowVisible(hWnd) && GetForegroundWindow() == hWnd; +} + bool FileExists(const std::string& path) { #ifdef OLD_WINDOWS diff --git a/src/windows/WinUtils.hpp b/src/windows/WinUtils.hpp index 08dd552..9995ed4 100644 --- a/src/windows/WinUtils.hpp +++ b/src/windows/WinUtils.hpp @@ -49,6 +49,7 @@ std::string GetStringFromHResult(HRESULT hr); LPTSTR GetTStringFromHResult(HRESULT hr); // Window utils +bool IsWindowActive(HWND hWnd); void WindowScroll(HWND hWnd, int diffUpDown); void WindowScrollXY(HWND hWnd, int diffLeftRight, int diffUpDown); void DrawBitmap(HDC hdc, HBITMAP bitmap, int x, int y, LPRECT clip = NULL, COLORREF transparent = CLR_NONE, int scaleToWidth = 0, int scaleToHeight = 0, bool hasAlpha = false); diff --git a/src/windows/WindowMessages.hpp b/src/windows/WindowMessages.hpp index 6c85d53..dcaef10 100644 --- a/src/windows/WindowMessages.hpp +++ b/src/windows/WindowMessages.hpp @@ -65,6 +65,8 @@ enum eWmUserMsgs WM_NOTIFMANAGERCALLBACK, WM_POSTINIT, WM_RECREATEMEMBERLIST, + WM_CLOSEBYPASSTRAY, WM_UPDATETEXTSIZE = WM_APP, // used by the MessageEditor + WM_RESTOREAPP, }; diff --git a/vs/DiscordMessenger.vcxproj b/vs/DiscordMessenger.vcxproj index 34638a0..c053c46 100644 --- a/vs/DiscordMessenger.vcxproj +++ b/vs/DiscordMessenger.vcxproj @@ -504,6 +504,7 @@ + @@ -568,6 +569,7 @@ + diff --git a/vs/DiscordMessenger.vcxproj.filters b/vs/DiscordMessenger.vcxproj.filters index 9735827..d8e5a39 100644 --- a/vs/DiscordMessenger.vcxproj.filters +++ b/vs/DiscordMessenger.vcxproj.filters @@ -629,6 +629,9 @@ Header Files\Discord + + Header Files\Windows + @@ -799,5 +802,8 @@ Source Files\Discord + + Source Files\Windows + \ No newline at end of file