From 4c74b882da6935c16b52dcaef4eda0f97e4bcf75 Mon Sep 17 00:00:00 2001 From: iProgramInCpp Date: Sun, 26 Jul 2026 20:47:20 +0300 Subject: [PATCH 01/14] add GetSysColorV2 and GetSysColorBrushV2 to support dark mode --- src/windows/WinUtils.cpp | 65 ++++++++++++++++++++++++++++++++++++++++ src/windows/WinUtils.hpp | 2 ++ 2 files changed, 67 insertions(+) diff --git a/src/windows/WinUtils.cpp b/src/windows/WinUtils.cpp index ed39d10..035f8ee 100644 --- a/src/windows/WinUtils.cpp +++ b/src/windows/WinUtils.cpp @@ -1743,3 +1743,68 @@ std::string FilterToken(const std::string& ogToken) return newToken; } + +bool IsDarkModeEnabled() +{ + return true;// TODO: load from LocalSettings. +} + +const COLORREF s_DarkModeColors[] = { + RGB(20,20,20), // COLOR_SCROLLBAR + RGB(40,40,40), // COLOR_BACKGROUND + RGB(0,0,0), // COLOR_ACTIVECAPTION + RGB(0,0,0), // COLOR_INACTIVECAPTION + RGB(40,40,40), // COLOR_MENU + RGB(0,0,0), // COLOR_WINDOW + RGB(80,80,80), // COLOR_WINDOWFRAME + RGB(255,255,255), // COLOR_MENUTEXT + RGB(255,255,255), // COLOR_WINDOWTEXT + RGB(255,255,255), // COLOR_CAPTIONTEXT + RGB(255,255,255), // COLOR_ACTIVEBORDER + RGB(255,255,255), // COLOR_INACTIVEBORDER + RGB(40,40,40), // COLOR_APPWORKSPACE + RGB(40,40,128), // COLOR_HIGHLIGHT + RGB(255,255,255), // COLOR_HIGHLIGHTTEXT + RGB(60,60,60), // COLOR_BTNFACE + RGB(20,20,20), // COLOR_BTNSHADOW + RGB(64,64,64), // COLOR_GRAYTEXT + RGB(255,255,255), // COLOR_BTNTEXT + RGB(128,128,128), // COLOR_INACTIVECAPTIONTEXT + RGB(80,80,80), // COLOR_BTNHIGHLIGHT + RGB(0,0,0), // COLOR_3DDKSHADOW + RGB(100,100,100), // COLOR_3DLIGHT + RGB(255,255,255), // COLOR_INFOTEXT + RGB(80,80,80), // COLOR_INFOBK + RGB(0,0,0), // missing #25 + RGB(255,0,255), // COLOR_HOTLIGHT + RGB(0,0,0), // COLOR_GRADIENTACTIVECAPTION + RGB(0,0,0), // COLOR_GRADIENTINACTIVECAPTION + RGB(40,40,128), // COLOR_MENUHILIGHT + RGB(30,30,30), // COLOR_MENUBAR +}; + +COLORREF GetSysColorV2(int nIndex) +{ + if (!IsDarkModeEnabled() || nIndex < 0 || nIndex >= 31) + return GetSysColor(nIndex); + + return s_DarkModeColors[nIndex]; +} + +HBRUSH GetSysColorBrushV2(int nIndex) +{ + if (!IsDarkModeEnabled()) + return GetSysColorBrush(nIndex); + + if (nIndex < 0 || nIndex >= 31) { + // fallback, but this usage is WRONG! + DbgPrintW("bad index %d used in GetSysColorBrushV2", nIndex); + return GetSysColorBrush(nIndex); + } + + static HBRUSH brushes[31]; + if (!brushes[nIndex]) + brushes[nIndex] = CreateSolidBrush(GetSysColorV2(nIndex)); + + return brushes[nIndex]; +} diff --git a/src/windows/WinUtils.hpp b/src/windows/WinUtils.hpp index fa70f27..b200649 100644 --- a/src/windows/WinUtils.hpp +++ b/src/windows/WinUtils.hpp @@ -150,6 +150,8 @@ COLORREF LerpColor(COLORREF a, COLORREF b, int progMul, int progDiv); bool IsColorDark(COLORREF cr); bool IsTextColorDark(); bool IsIconMostlyBlack(HICON hic); +COLORREF GetSysColorV2(int nIndex); +HBRUSH GetSysColorBrushV2(int nIndex); #define IsColorLight(cr) (!IsColorDark(cr)) #define IsTextColorLight() (!IsTextColorDark()) From 312180f21b9b8d024bed16643f80a94e3aafeddd Mon Sep 17 00:00:00 2001 From: iProgramInCpp Date: Sun, 26 Jul 2026 20:54:48 +0300 Subject: [PATCH 02/14] first pass --- src/windows/AutoComplete.cpp | 14 +++--- src/windows/ChannelView.cpp | 22 ++++----- src/windows/ChannelViewOld.cpp | 2 +- src/windows/GuildHeader.cpp | 14 +++--- src/windows/GuildLister.cpp | 16 +++---- src/windows/ImageViewer.cpp | 6 +-- src/windows/LoadingMessage.cpp | 6 +-- src/windows/Main.cpp | 2 +- src/windows/MemberList.cpp | 22 ++++----- src/windows/MemberListOld.cpp | 2 +- src/windows/MessageEditor.cpp | 8 ++-- src/windows/MessageList.cpp | 74 ++++++++++++++--------------- src/windows/ProfilePopout.cpp | 6 +-- src/windows/ProfileView.cpp | 8 ++-- src/windows/QuickSwitcher.cpp | 12 ++--- src/windows/RoleList.cpp | 12 ++--- src/windows/StatusBar.cpp | 2 +- src/windows/TextInterface_Win32.cpp | 12 ++--- src/windows/WinUtils.cpp | 14 +++--- 19 files changed, 127 insertions(+), 127 deletions(-) diff --git a/src/windows/AutoComplete.cpp b/src/windows/AutoComplete.cpp index 8afc203..74561e3 100644 --- a/src/windows/AutoComplete.cpp +++ b/src/windows/AutoComplete.cpp @@ -331,7 +331,7 @@ bool AutoComplete::InitializeClass() WNDCLASS wc; ZeroMemory(&wc, sizeof wc); wc.lpszClassName = T_AUTOCOMPLETE_CLASS; - wc.hbrBackground = ri::GetSysColorBrush(COLOR_3DFACE); + wc.hbrBackground = GetSysColorBrushV2(COLOR_3DFACE); wc.style = 0; wc.hCursor = LoadCursor (0, IDC_ARROW); wc.lpfnWndProc = AutoComplete::WndProc; @@ -506,16 +506,16 @@ LRESULT AutoComplete::HandleCustomDraw(HWND hWnd, NMLVCUSTOMDRAW* pInfo) int sta = ListView_GetItemState(hList, idx, LVIS_SELECTED); if (sta & LVIS_SELECTED) { - pInfo->clrTextBk = GetSysColor(COLOR_HIGHLIGHT); - pInfo->clrText = GetSysColor(COLOR_HIGHLIGHTTEXT); + pInfo->clrTextBk = GetSysColorV2(COLOR_HIGHLIGHT); + pInfo->clrText = GetSysColorV2(COLOR_HIGHLIGHTTEXT); } else if (pInfo->iSubItem == COL_SUBNAME) { - pInfo->clrTextBk = GetSysColor(COLOR_WINDOW); - pInfo->clrText = GetSysColor(COLOR_GRAYTEXT); + pInfo->clrTextBk = GetSysColorV2(COLOR_WINDOW); + pInfo->clrText = GetSysColorV2(COLOR_GRAYTEXT); } else { - pInfo->clrTextBk = GetSysColor(COLOR_WINDOW); - pInfo->clrText = GetSysColor(COLOR_MENUTEXT); + pInfo->clrTextBk = GetSysColorV2(COLOR_WINDOW); + pInfo->clrText = GetSysColorV2(COLOR_MENUTEXT); } return CDRF_NEWFONT; diff --git a/src/windows/ChannelView.cpp b/src/windows/ChannelView.cpp index 46bb249..2f81e49 100644 --- a/src/windows/ChannelView.cpp +++ b/src/windows/ChannelView.cpp @@ -509,7 +509,7 @@ void ChannelView::InitializeClass() WNDCLASS& wc = g_ChannelViewClass; wc.lpszClassName = T_CHANNEL_VIEW_CONTAINER_CLASS; - wc.hbrBackground = ri::GetSysColorBrush(COLOR_3DFACE); + wc.hbrBackground = GetSysColorBrushV2(COLOR_3DFACE); wc.style = 0; wc.hCursor = LoadCursor(0, IDC_ARROW); wc.lpfnWndProc = &ChannelView::WndProc; @@ -691,27 +691,27 @@ LRESULT ChannelView::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) ChannelMember* pMember = &pView->m_channels[lpdis->itemID]; Channel* pChan = GetDiscordInstance()->GetChannel(pMember->m_snowflake); - COLORREF nameTextColor = GetSysColor(COLOR_WINDOWTEXT); - COLORREF statusTextColor = GetSysColor(COLOR_GRAYTEXT); - COLORREF backgdColor = GetSysColor(COLOR_WINDOW); + COLORREF nameTextColor = GetSysColorV2(COLOR_WINDOWTEXT); + COLORREF statusTextColor = GetSysColorV2(COLOR_GRAYTEXT); + COLORREF backgdColor = GetSysColorV2(COLOR_WINDOW); if (pView->m_hotItem == lpdis->itemID) { - FillRect(lpdis->hDC, &lpdis->rcItem, ri::GetSysColorBrush(COLOR_MENUBAR)); - backgdColor = GetSysColor(COLOR_MENUBAR); + FillRect(lpdis->hDC, &lpdis->rcItem, GetSysColorBrushV2(COLOR_MENUBAR)); + backgdColor = GetSysColorV2(COLOR_MENUBAR); } else { // Windows 2000 doesn't do automatic clearing - FillRect(lpdis->hDC, &lpdis->rcItem, ri::GetSysColorBrush(COLOR_WINDOW)); + FillRect(lpdis->hDC, &lpdis->rcItem, GetSysColorBrushV2(COLOR_WINDOW)); } if (lpdis->itemState & ODS_SELECTED) { - FillRect(lpdis->hDC, &lpdis->rcItem, ri::GetSysColorBrush(COLOR_HIGHLIGHT)); - backgdColor = GetSysColor(COLOR_HIGHLIGHT); - nameTextColor = GetSysColor(COLOR_HIGHLIGHTTEXT); - statusTextColor = GetSysColor(COLOR_HIGHLIGHTTEXT); + FillRect(lpdis->hDC, &lpdis->rcItem, GetSysColorBrushV2(COLOR_HIGHLIGHT)); + backgdColor = GetSysColorV2(COLOR_HIGHLIGHT); + nameTextColor = GetSysColorV2(COLOR_HIGHLIGHTTEXT); + statusTextColor = GetSysColorV2(COLOR_HIGHLIGHTTEXT); } // draw profile picture frame diff --git a/src/windows/ChannelViewOld.cpp b/src/windows/ChannelViewOld.cpp index a64c97f..ce137d7 100644 --- a/src/windows/ChannelViewOld.cpp +++ b/src/windows/ChannelViewOld.cpp @@ -58,7 +58,7 @@ void ChannelViewOld::InitializeClass() WNDCLASS& wc = g_ChannelViewLegacyClass; wc.lpszClassName = T_CHANNEL_VIEW_CONTAINER_CLASS2; - wc.hbrBackground = ri::GetSysColorBrush(COLOR_3DFACE); + wc.hbrBackground = GetSysColorBrushV2(COLOR_3DFACE); wc.style = 0; wc.hCursor = LoadCursor(0, IDC_ARROW); wc.lpfnWndProc = &ChannelViewOld::WndProc; diff --git a/src/windows/GuildHeader.cpp b/src/windows/GuildHeader.cpp index 627e97c..6b03714 100644 --- a/src/windows/GuildHeader.cpp +++ b/src/windows/GuildHeader.cpp @@ -182,8 +182,8 @@ void GuildHeader::DrawButton(HDC hdc, Button& button) MoveToEx(hdc, 0, 0, &oldPt); const int clr = GUILD_HEADER_COLOR_2; - COLORREF clrA = LerpColor(RGB(255, 255, 255), GetSysColor(clr), 1, 2); - COLORREF clrB = LerpColor(RGB(0, 0, 0), GetSysColor(clr), 1, 2); + COLORREF clrA = LerpColor(RGB(255, 255, 255), GetSysColorV2(clr), 1, 2); + COLORREF clrB = LerpColor(RGB(0, 0, 0), GetSysColorV2(clr), 1, 2); RECT exp = { iconX - 4, iconY - 4, iconX + 4 + iconSize, iconY + 4 + iconSize }; exp.left = std::max(exp.left, button.m_rect.left); @@ -199,7 +199,7 @@ void GuildHeader::DrawButton(HDC hdc, Button& button) DeleteRgn(rgn); } else { - FillRect(hdc, &exp, ri::GetSysColorBrush(clr)); + FillRect(hdc, &exp, GetSysColorBrushV2(clr)); } if (button.m_held) { @@ -418,8 +418,8 @@ LRESULT CALLBACK GuildHeader::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA HDC hdc = BeginPaint(hWnd, &ps); - COLORREF old = SetBkColor(hdc, GetSysColor(GUILD_HEADER_COLOR)); - COLORREF oldText = SetTextColor(hdc, GetSysColor(COLOR_CAPTIONTEXT)); + COLORREF old = SetBkColor(hdc, GetSysColorV2(GUILD_HEADER_COLOR)); + COLORREF oldText = SetTextColor(hdc, GetSysColorV2(COLOR_CAPTIONTEXT)); pThis->Layout(); @@ -427,9 +427,9 @@ LRESULT CALLBACK GuildHeader::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA #if (WINVER>=0x0500) FillGradient(hdc, &pThis->m_rectLeftFull, GUILD_HEADER_COLOR, GUILD_HEADER_COLOR_2, false); FillGradient(hdc, &pThis->m_rectRightFull, GUILD_HEADER_COLOR_2, GUILD_HEADER_COLOR, false); - FillRect(hdc, &pThis->m_rectMidFull, ri::GetSysColorBrush(GUILD_HEADER_COLOR_2)); + FillRect(hdc, &pThis->m_rectMidFull, GetSysColorBrushV2(GUILD_HEADER_COLOR_2)); #else - FillRect(hdc, &pThis->m_rectFull, ri::GetSysColorBrush(GUILD_HEADER_COLOR)); + FillRect(hdc, &pThis->m_rectFull, GetSysColorBrushV2(GUILD_HEADER_COLOR)); #endif int old_mode = SetBkMode(hdc, TRANSPARENT); diff --git a/src/windows/GuildLister.cpp b/src/windows/GuildLister.cpp index 2c8d57e..e8e9a49 100644 --- a/src/windows/GuildLister.cpp +++ b/src/windows/GuildLister.cpp @@ -523,7 +523,7 @@ void GuildLister::DrawServerIcon(HDC hdc, HBITMAP hicon, int& y, RECT& rect, Sno int pfpBorderSize2 = GetProfileBorderRenderSize(); - FillRect(hdc, &rcProfile, ri::GetSysColorBrush(GUILD_LISTER_COLOR)); + FillRect(hdc, &rcProfile, GetSysColorBrushV2(GUILD_LISTER_COLOR)); if (currentFolder) { HRGN hrgn = DoubleBufferingHelper::CreateRectRgn(hdc, rcProfile); @@ -535,7 +535,7 @@ void GuildLister::DrawServerIcon(HDC hdc, HBITMAP hicon, int& y, RECT& rect, Sno } HGDIOBJ oldBrush, oldPen; - oldBrush = SelectObject(hdc, ri::GetSysColorBrush(COLOR_BTNSHADOW)); + oldBrush = SelectObject(hdc, GetSysColorBrushV2(COLOR_BTNSHADOW)); oldPen = SelectObject(hdc, GetStockObject(BLACK_PEN)); if (currentFolder == (id & ~BIT_FOLDER)) { @@ -701,8 +701,8 @@ void GuildLister::Paint(HWND hWnd, HDC hdc, RECT& rcPaint) RECT rc = rect; rc.top += y; rc.bottom = rc.top + C_GUILD_GAP_HEIGHT; - FillRect(hdc, &rc, ri::GetSysColorBrush(GUILD_LISTER_COLOR)); - COLORREF oldPenColor = ri::SetDCPenColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); + FillRect(hdc, &rc, GetSysColorBrushV2(GUILD_LISTER_COLOR)); + COLORREF oldPenColor = ri::SetDCPenColor(hdc, GetSysColorV2(COLOR_WINDOWTEXT)); HGDIOBJ oldobj = SelectObject(hdc, ri::GetDCPen()); POINT pt2; MoveToEx(hdc, rc.left + BORDER_SIZE, rc.top + BORDER_SIZE, &pt2); @@ -782,9 +782,9 @@ void GuildLister::Paint(HWND hWnd, HDC hdc, RECT& rcPaint) finalRect.top = y; //if (initialRect.top < initialRect.bottom) - // FillRect(hdc, &initialRect, ri::GetSysColorBrush(GUILD_LISTER_COLOR)); + // FillRect(hdc, &initialRect, GetSysColorBrushV2(GUILD_LISTER_COLOR)); //if (finalRect.top < finalRect.bottom) - // FillRect(hdc, &finalRect, ri::GetSysColorBrush(GUILD_LISTER_COLOR)); + // FillRect(hdc, &finalRect, GetSysColorBrushV2(GUILD_LISTER_COLOR)); MoveToEx(hdc, pt.x, pt.y, NULL); } @@ -1185,7 +1185,7 @@ LRESULT CALLBACK GuildLister::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA if (ShouldUseDoubleBuffering()) { DoubleBufferingHelper helper(hdc, paintRect); - FillRect(helper.HdcMem(), &paintRect, ri::GetSysColorBrush(GUILD_LISTER_COLOR)); + FillRect(helper.HdcMem(), &paintRect, GetSysColorBrushV2(GUILD_LISTER_COLOR)); pThis->Paint(hWnd, helper.HdcMem(), paintRect); } else @@ -1382,7 +1382,7 @@ void GuildLister::InitializeClass() WNDCLASS& wc = g_GuildListerClass; wc.lpszClassName = T_GUILD_LISTER_CLASS; - wc.hbrBackground = ri::GetSysColorBrush(GUILD_LISTER_COLOR); + wc.hbrBackground = GetSysColorBrushV2(GUILD_LISTER_COLOR); wc.style = 0; wc.hCursor = LoadCursor(0, IDC_ARROW); wc.lpfnWndProc = GuildLister::WndProc; diff --git a/src/windows/ImageViewer.cpp b/src/windows/ImageViewer.cpp index 8a3f396..cb6b9f4 100644 --- a/src/windows/ImageViewer.cpp +++ b/src/windows/ImageViewer.cpp @@ -287,7 +287,7 @@ LRESULT CALLBACK ImageViewerChildWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LP HImage* him = GetBitmap(); if (!him) { - COLORREF oldBk = SetBkColor(hdc, GetSysColor (COLOR_3DDKSHADOW)); + COLORREF oldBk = SetBkColor(hdc, GetSysColorV2 (COLOR_3DDKSHADOW)); COLORREF oldText = SetTextColor(hdc, RGB(255, 255, 255)); HGDIOBJ oldObject = SelectObject(hdc, g_MessageTextFont); @@ -491,7 +491,7 @@ bool RegisterImageViewerClass() wc.lpfnWndProc = ImageViewerWndProc; wc.hInstance = g_hInstance; wc.lpszClassName = DM_IMAGE_VIEWER_CLASS; - wc.hbrBackground = ri::GetSysColorBrush(COLOR_3DFACE); + wc.hbrBackground = GetSysColorBrushV2(COLOR_3DFACE); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hIcon = g_Icon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_ICON)); @@ -501,7 +501,7 @@ bool RegisterImageViewerClass() wc2.lpfnWndProc = ImageViewerChildWndProc; wc2.hInstance = g_hInstance; wc2.lpszClassName = DM_IMAGE_VIEWER_CHILD_CLASS; - wc2.hbrBackground = ri::GetSysColorBrush(COLOR_3DDKSHADOW); + wc2.hbrBackground = GetSysColorBrushV2(COLOR_3DDKSHADOW); wc2.hCursor = LoadCursor(NULL, IDC_ARROW); wc2.hIcon = g_Icon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_ICON)); diff --git a/src/windows/LoadingMessage.cpp b/src/windows/LoadingMessage.cpp index d8c0142..7d796d2 100644 --- a/src/windows/LoadingMessage.cpp +++ b/src/windows/LoadingMessage.cpp @@ -130,8 +130,8 @@ LRESULT CALLBACK LoadingMessage::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LP RECT textRect = rect; textRect.top += MulDiv(textRect.bottom - textRect.top, 3, 4); HGDIOBJ old = SelectObject(hdc, g_AuthorTextFont); - COLORREF oldClr = SetBkColor(hdc, GetSysColor(COLOR_3DFACE)); - COLORREF oldTClr = SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); + COLORREF oldClr = SetBkColor(hdc, GetSysColorV2(COLOR_3DFACE)); + COLORREF oldTClr = SetTextColor(hdc, GetSysColorV2(COLOR_WINDOWTEXT)); DrawText(hdc, TEXT("Please wait, connecting to Discord..."), -1, &textRect, DT_CENTER); @@ -161,7 +161,7 @@ void LoadingMessage::InitializeClass() return; wc.lpszClassName = T_LOADING_MESSAGE_CLASS; - wc.hbrBackground = ri::GetSysColorBrush(COLOR_3DFACE); + wc.hbrBackground = GetSysColorBrushV2(COLOR_3DFACE); wc.style = CS_HREDRAW; wc.hCursor = LoadCursor(0, IDC_WAIT); wc.lpfnWndProc = LoadingMessage::WndProc; diff --git a/src/windows/Main.cpp b/src/windows/Main.cpp index f69fd4b..a49b5d0 100644 --- a/src/windows/Main.cpp +++ b/src/windows/Main.cpp @@ -1978,7 +1978,7 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLin g_pHTTPClient = new NetworkerThreadManager; // Create a background brush. - g_backgroundBrush = ri::GetSysColorBrush(COLOR_3DFACE); + g_backgroundBrush = GetSysColorBrushV2(COLOR_3DFACE); SetupCachePathIfNeeded(); diff --git a/src/windows/MemberList.cpp b/src/windows/MemberList.cpp index c734a48..809b6bb 100644 --- a/src/windows/MemberList.cpp +++ b/src/windows/MemberList.cpp @@ -365,30 +365,30 @@ LRESULT MemberList::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) Profile* pf = GetProfileCache()->LookupProfile(user, "", "", "", false); COLORREF nameTextColor = 0; - COLORREF statusTextColor = GetSysColor(COLOR_GRAYTEXT); - COLORREF backgdColor = GetSysColor(COLOR_WINDOW); + COLORREF statusTextColor = GetSysColorV2(COLOR_GRAYTEXT); + COLORREF backgdColor = GetSysColorV2(COLOR_WINDOW); nameTextColor = GetNameColor(pf, pList->m_guild); if (nameTextColor == CLR_NONE) - nameTextColor = GetSysColor(COLOR_WINDOWTEXT); + nameTextColor = GetSysColorV2(COLOR_WINDOWTEXT); if (pList->m_hotItem == lpdis->itemID) { - FillRect(lpdis->hDC, &lpdis->rcItem, ri::GetSysColorBrush(COLOR_MENUBAR)); - backgdColor = GetSysColor(COLOR_MENUBAR); + FillRect(lpdis->hDC, &lpdis->rcItem, GetSysColorBrushV2(COLOR_MENUBAR)); + backgdColor = GetSysColorV2(COLOR_MENUBAR); } else { // Windows 2000 doesn't do automatic clearing - FillRect(lpdis->hDC, &lpdis->rcItem, ri::GetSysColorBrush(COLOR_WINDOW)); + FillRect(lpdis->hDC, &lpdis->rcItem, GetSysColorBrushV2(COLOR_WINDOW)); } if (lpdis->itemState & ODS_SELECTED) { - FillRect(lpdis->hDC, &lpdis->rcItem, ri::GetSysColorBrush(COLOR_HIGHLIGHT)); - backgdColor = GetSysColor(COLOR_HIGHLIGHT); - nameTextColor = GetSysColor(COLOR_HIGHLIGHTTEXT); - statusTextColor = GetSysColor(COLOR_HIGHLIGHTTEXT); + FillRect(lpdis->hDC, &lpdis->rcItem, GetSysColorBrushV2(COLOR_HIGHLIGHT)); + backgdColor = GetSysColorV2(COLOR_HIGHLIGHT); + nameTextColor = GetSysColorV2(COLOR_HIGHLIGHTTEXT); + statusTextColor = GetSysColorV2(COLOR_HIGHLIGHTTEXT); } int textOffset = 0; @@ -541,7 +541,7 @@ void MemberList::InitializeClass() WNDCLASS& wc = g_MemberListClass; wc.lpszClassName = T_MEMBER_LIST_CLASS; - wc.hbrBackground = ri::GetSysColorBrush(COLOR_3DFACE); + wc.hbrBackground = GetSysColorBrushV2(COLOR_3DFACE); wc.style = 0; wc.hCursor = LoadCursor(0, IDC_ARROW); wc.lpfnWndProc = &MemberList::WndProc; diff --git a/src/windows/MemberListOld.cpp b/src/windows/MemberListOld.cpp index 88e6ae0..cb7ea17 100644 --- a/src/windows/MemberListOld.cpp +++ b/src/windows/MemberListOld.cpp @@ -59,7 +59,7 @@ void MemberListOld::InitializeClass() WNDCLASS& wc = g_memberListOldClass; wc.lpszClassName = T_MEMBER_LIST_CLASS_OLD; - wc.hbrBackground = ri::GetSysColorBrush(COLOR_3DFACE); + wc.hbrBackground = GetSysColorBrushV2(COLOR_3DFACE); wc.style = 0; wc.hCursor = LoadCursor(0, IDC_ARROW); wc.lpfnWndProc = &MemberListOld::WndProc; diff --git a/src/windows/MessageEditor.cpp b/src/windows/MessageEditor.cpp index 7a7e9b0..59f2872 100644 --- a/src/windows/MessageEditor.cpp +++ b/src/windows/MessageEditor.cpp @@ -289,7 +289,7 @@ void MessageEditor::StartReply(Snowflake messageID, Snowflake authorID) } if (clr == CLR_NONE) - clr = GetSysColor(COLOR_WINDOWTEXT); + clr = GetSysColorV2(COLOR_WINDOWTEXT); m_userNameColor = clr; } @@ -871,8 +871,8 @@ LRESULT MessageEditor::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara if ((HWND) lParam == pThis->m_mentionName_hwnd) SetTextColor((HDC) wParam, pThis->m_userNameColor); - SetBkColor((HDC) wParam, GetSysColor(COLOR_3DFACE)); - return (LRESULT)ri::GetSysColorBrush(COLOR_3DFACE); + SetBkColor((HDC) wParam, GetSysColorV2(COLOR_3DFACE)); + return (LRESULT)GetSysColorBrushV2(COLOR_3DFACE); } } @@ -884,7 +884,7 @@ void MessageEditor::InitializeClass() WNDCLASS wc; ZeroMemory(&wc, sizeof wc); wc.lpszClassName = T_MESSAGE_EDITOR_CLASS; - wc.hbrBackground = ri::GetSysColorBrush(COLOR_3DFACE); + wc.hbrBackground = GetSysColorBrushV2(COLOR_3DFACE); wc.style = 0; wc.hCursor = LoadCursor (0, IDC_ARROW); wc.lpfnWndProc = MessageEditor::WndProc; diff --git a/src/windows/MessageList.cpp b/src/windows/MessageList.cpp index 5158be4..ae51a1f 100644 --- a/src/windows/MessageList.cpp +++ b/src/windows/MessageList.cpp @@ -59,7 +59,7 @@ static const int g_WelcomeTextCount = _countof(g_WelcomeTextIds); MessageList::MessageList() { - m_defaultBackgroundBrush = ri::GetSysColorBrush(COLOR_WINDOW); + m_defaultBackgroundBrush = GetSysColorBrushV2(COLOR_WINDOW); // This ugly hack allows me to calculate the offset between GMT and // local time. This is used when calculating date gaps. @@ -277,7 +277,7 @@ void RichEmbedItem::Draw(HDC hdc, RECT& messageRect, MessageList* pList) rcGradient.left += ScaleByDPI(4); COLORREF oldColor = SetBkColor(hdc, pList->GetDarkerBackgroundColor()); if (GetLocalSettings()->GetMessageStyle() == MS_GRADIENT) { - FillGradientColors(hdc, &rcGradient, GetSysColor(COLOR_WINDOWFRAME), CLR_NONE, true); + FillGradientColors(hdc, &rcGradient, GetSysColorV2(COLOR_WINDOWFRAME), CLR_NONE, true); } else { COLORREF oldClr = ri::SetDCBrushColor(hdc, pList->GetDarkerBackgroundColor()); @@ -299,7 +299,7 @@ void RichEmbedItem::Draw(HDC hdc, RECT& messageRect, MessageList* pList) rc.right -= borderSize; rc.bottom -= borderSize; HGDIOBJ oldObj = SelectObject(hdc, GetStockFont(ANSI_VAR_FONT)); - COLORREF windowTextColor = pList->InvertIfNeeded(GetSysColor(COLOR_WINDOWTEXT)); + COLORREF windowTextColor = pList->InvertIfNeeded(GetSysColorV2(COLOR_WINDOWTEXT)); if (m_providerSize.cy) { SelectObject(hdc, g_ReplyTextFont); @@ -1537,7 +1537,7 @@ void MessageList::DrawDefaultAttachment(HDC hdc, RECT& paintRect, AttachmentItem if (attachItem.m_bHighlighted && inView) old = SetTextColor(hdc, RGB(0, 0, 255)); else - old = SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); + old = SetTextColor(hdc, GetSysColorV2(COLOR_WINDOWTEXT)); LPCTSTR name = attachItem.m_nameText; RECT rcMeasure; @@ -1575,7 +1575,7 @@ void MessageList::DrawDefaultAttachment(HDC hdc, RECT& paintRect, AttachmentItem attachItem.m_textRect = textRect; - uint32_t oc = SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); + uint32_t oc = SetTextColor(hdc, GetSysColorV2(COLOR_WINDOWTEXT)); if (old == CLR_NONE) old = oc; @@ -1991,7 +1991,7 @@ void MessageList::DrawReplyPieceIcon(HDC hdc, int leftX, int topY) return; } - HPEN hpen = CreatePen(PS_SOLID, 3, InvertIfNeeded(GetSysColor(COLOR_WINDOWTEXT))); + HPEN hpen = CreatePen(PS_SOLID, 3, InvertIfNeeded(GetSysColorV2(COLOR_WINDOWTEXT))); HGDIOBJ old = SelectObject(hdc, hpen); POINT ptold = {}; @@ -2092,7 +2092,7 @@ int MessageList::DrawMessageReply(HDC hdc, MessageItem& item, RECT& rc) } if (nameClr == CLR_NONE) - nameClr = InvertIfNeeded(GetSysColor(COLOR_WINDOWTEXT)); + nameClr = InvertIfNeeded(GetSysColorV2(COLOR_WINDOWTEXT)); LPCTSTR strPart1 = TEXT(""); LPCTSTR strPart2 = NULL; @@ -2133,7 +2133,7 @@ int MessageList::DrawMessageReply(HDC hdc, MessageItem& item, RECT& rc) } // Draw the text - COLORREF old = SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT)); + COLORREF old = SetTextColor(hdc, GetSysColorV2(COLOR_GRAYTEXT)); SelectObject(hdc, g_ReplyTextFont); RECT rcMeasure{}; @@ -2155,7 +2155,7 @@ int MessageList::DrawMessageReply(HDC hdc, MessageItem& item, RECT& rc) if (!isActionMessage) rcReply.left += ScaleByDPI(5); - SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT)); + SetTextColor(hdc, GetSysColorV2(COLOR_GRAYTEXT)); if (STRAVAILABLE(strPart2)) { @@ -2230,9 +2230,9 @@ void MessageList::DrawMessage(HDC hdc, MessageItem& item, RECT& msgRect, RECT& c bool isFlashed = (m_emphasizedMessage == item.m_msg->m_snowflake) && (m_flash_counter % 2 != 0); - COLORREF chosenTextColor = GetSysColor(COLOR_WINDOWTEXT); + COLORREF chosenTextColor = GetSysColorV2(COLOR_WINDOWTEXT); if (item.m_msg->m_bRead) - chosenTextColor = GetSysColor(COLOR_3DSHADOW); + chosenTextColor = GetSysColorV2(COLOR_3DSHADOW); COLORREF textColor = InvertIfNeeded(chosenTextColor), bkgdColor = CLR_NONE; @@ -2260,7 +2260,7 @@ void MessageList::DrawMessage(HDC hdc, MessageItem& item, RECT& msgRect, RECT& c LPTSTR strDateGap = ConvertCppStringToTString(" " + item.m_msg->m_dateOnly + " "); - COLORREF clrText = InvertIfNeeded(bDrawNewMarker ? NEW_MARKER_COLOR : GetSysColor(COLOR_GRAYTEXT)); + COLORREF clrText = InvertIfNeeded(bDrawNewMarker ? NEW_MARKER_COLOR : GetSysColorV2(COLOR_GRAYTEXT)); COLORREF oldTextClr = SetTextColor(hdc, clrText); COLORREF oldPenClr = ri::SetDCPenColor(hdc, clrText); @@ -2270,13 +2270,13 @@ void MessageList::DrawMessage(HDC hdc, MessageItem& item, RECT& msgRect, RECT& c if (mStyle == MS_FLATBR) clr = COLOR_WINDOW; else if (mStyle == MS_GRADIENT) { COLORREF c1, c2; - c1 = GetSysColor(COLOR_WINDOW); // high - c2 = GetSysColor(COLOR_3DFACE); // low + c1 = GetSysColorV2(COLOR_WINDOW); // high + c2 = GetSysColorV2(COLOR_3DFACE); // low if (c1 < c2) clr = COLOR_3DFACE; else clr = COLOR_WINDOW; } - FillRect(hdc, &dgRect, ri::GetSysColorBrush(clr)); + FillRect(hdc, &dgRect, GetSysColorBrushV2(clr)); } else { @@ -2339,27 +2339,27 @@ void MessageList::DrawMessage(HDC hdc, MessageItem& item, RECT& msgRect, RECT& c else rect2.top -= 4; if (!isFlashed) - bkgdColor = GetSysColor(COLOR_3DFACE); + bkgdColor = GetSysColorV2(COLOR_3DFACE); if (item.m_msg->m_type != MessageType::CHANNEL_HEADER) { ri::DrawEdge(hdc, &rect2, BDR_RAISED, edgeFlags); } else if (edgeFlags & BF_MIDDLE) { - FillRect(hdc, &rect2, ri::GetSysColorBrush(COLOR_3DFACE)); + FillRect(hdc, &rect2, GetSysColorBrushV2(COLOR_3DFACE)); } break; } case MS_FLAT: { if (!isFlashed) { - bkgdColor = GetSysColor(COLOR_3DFACE); - FillRect(hdc, &msgRect, ri::GetSysColorBrush(COLOR_3DFACE)); + bkgdColor = GetSysColorV2(COLOR_3DFACE); + FillRect(hdc, &msgRect, GetSysColorBrushV2(COLOR_3DFACE)); } break; } case MS_FLATBR: { if (!isFlashed) { - bkgdColor = GetSysColor(COLOR_WINDOW); - FillRect(hdc, &msgRect, ri::GetSysColorBrush(COLOR_WINDOW)); + bkgdColor = GetSysColorV2(COLOR_WINDOW); + FillRect(hdc, &msgRect, GetSysColorBrushV2(COLOR_WINDOW)); } break; } @@ -2369,8 +2369,8 @@ void MessageList::DrawMessage(HDC hdc, MessageItem& item, RECT& msgRect, RECT& c break; COLORREF c1, c2; - c1 = GetSysColor(COLOR_WINDOW); // high - c2 = GetSysColor(COLOR_3DFACE); // low + c1 = GetSysColorV2(COLOR_WINDOW); // high + c2 = GetSysColorV2(COLOR_3DFACE); // low bool swapped = false; if (c1 < c2) { @@ -2392,7 +2392,7 @@ void MessageList::DrawMessage(HDC hdc, MessageItem& item, RECT& msgRect, RECT& c if (isChainCont) { // Just render a flat background using the bottom color - FillRect(hdc, &msgRect, ri::GetSysColorBrush(swapped ? COLOR_WINDOW : COLOR_3DFACE)); + FillRect(hdc, &msgRect, GetSysColorBrushV2(swapped ? COLOR_WINDOW : COLOR_3DFACE)); break; } @@ -2779,7 +2779,7 @@ void MessageList::DrawMessage(HDC hdc, MessageItem& item, RECT& msgRect, RECT& c if (item.m_msg->m_type == MessageType::UNSENT_MESSAGE) oldTextColor = SetTextColor(hdc, RGB(255, 0, 0)); else if (item.m_msg->m_type == MessageType::SENDING_MESSAGE) - oldTextColor = SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT)); + oldTextColor = SetTextColor(hdc, GetSysColorV2(COLOR_GRAYTEXT)); item.m_message.Draw(&mddc, offsetY); @@ -2788,7 +2788,7 @@ void MessageList::DrawMessage(HDC hdc, MessageItem& item, RECT& msgRect, RECT& c if (oldTextColor != CLR_NONE) SetTextColor(hdc, oldTextColor); - COLORREF windowTextColor = InvertIfNeeded(GetSysColor(COLOR_WINDOWTEXT)); + COLORREF windowTextColor = InvertIfNeeded(GetSysColorV2(COLOR_WINDOWTEXT)); for (size_t i = 0; i < item.m_interactableData.size(); i++) { InteractableItem& iitem = item.m_interactableData[i]; @@ -3132,11 +3132,11 @@ void MessageList::Paint(HDC hdc, RECT& paintRect) case MS_GRADIENT: { oldBkMode = SetBkMode(hdc, TRANSPARENT); oldBkModeSet = true; - chosenBkColor = GetSysColor(COLOR_3DFACE); + chosenBkColor = GetSysColorV2(COLOR_3DFACE); break; } case MS_FLATBR: { - chosenBkColor = GetSysColor(COLOR_WINDOW); + chosenBkColor = GetSysColorV2(COLOR_WINDOW); oldBkColor = SetBkColor(hdc, chosenBkColor); break; } @@ -3147,7 +3147,7 @@ void MessageList::Paint(HDC hdc, RECT& paintRect) break; } default: { - chosenBkColor = GetSysColor(COLOR_3DFACE); + chosenBkColor = GetSysColorV2(COLOR_3DFACE); oldBkColor = SetBkColor(hdc, chosenBkColor); break; } @@ -3155,7 +3155,7 @@ void MessageList::Paint(HDC hdc, RECT& paintRect) DrawingContext mddc(hdc); mddc.SetBackgroundColor(chosenBkColor); - mddc.SetInvertTextColor(InvertIfNeeded(GetSysColor(COLOR_WINDOWTEXT))); + mddc.SetInvertTextColor(InvertIfNeeded(GetSysColorV2(COLOR_WINDOWTEXT))); Snowflake lastDrawnMessage = 0; Snowflake lastKnownMessage = 0; @@ -4140,7 +4140,7 @@ void MessageList::InitializeClass() WNDCLASS& wc = g_MsgListClass; wc.lpszClassName = T_MESSAGE_LIST_CLASS; - wc.hbrBackground = ri::GetSysColorBrush(COLOR_3DFACE); + wc.hbrBackground = GetSysColorBrushV2(COLOR_3DFACE); wc.style = 0; wc.lpfnWndProc = MessageList::WndProc; wc.hCursor = LoadCursor(0, IDC_ARROW); @@ -4164,7 +4164,7 @@ void MessageList::UpdateBackgroundBrush() if (mode == MS_IMAGE) SetClassLongPtr(m_hwnd, GCLP_HBRBACKGROUND, (LONG_PTR) m_backgroundBrush); else - SetClassLongPtr(m_hwnd, GCLP_HBRBACKGROUND, (LONG_PTR) ri::GetSysColorBrush(bru)); + SetClassLongPtr(m_hwnd, GCLP_HBRBACKGROUND, (LONG_PTR) GetSysColorBrushV2(bru)); } bool MessageList::SendToMessage(Snowflake sf, bool requestIfNeeded, bool forceInvalidate) @@ -4457,8 +4457,8 @@ void MessageList::ReloadBackground() if (m_bBackgroundHasAlpha) { - m_backgroundColor = GetSysColor(COLOR_WINDOW); - m_backgroundBrush = ri::GetSysColorBrush(COLOR_WINDOW); + m_backgroundColor = GetSysColorV2(COLOR_WINDOW); + m_backgroundBrush = GetSysColorBrushV2(COLOR_WINDOW); m_bDontDeleteBackgroundBrush = true; } else @@ -4486,7 +4486,7 @@ void MessageList::ReloadBackground() m_bDontDeleteBackgroundBrush = false; } - m_bInvertTextColors = IsColorDark(m_backgroundColor) ^ (!IsColorDark(GetSysColor(COLOR_WINDOWTEXT))); + m_bInvertTextColors = IsColorDark(m_backgroundColor) ^ (!IsColorDark(GetSysColorV2(COLOR_WINDOWTEXT))); } void MessageList::UnloadBackground() @@ -4554,9 +4554,9 @@ COLORREF MessageList::GetDarkerBackgroundColor() const if (style == MS_IMAGE) bgColor = m_backgroundColor; else if (style == MS_FLATBR) - bgColor = GetSysColor(COLOR_WINDOW); + bgColor = GetSysColorV2(COLOR_WINDOW); else - bgColor = GetSysColor(COLOR_3DFACE); + bgColor = GetSysColorV2(COLOR_3DFACE); COLORREF hint = IsColorDark(bgColor) ? 0xFFFFFF : 0x000000; diff --git a/src/windows/ProfilePopout.cpp b/src/windows/ProfilePopout.cpp index 76d61bf..a87913b 100644 --- a/src/windows/ProfilePopout.cpp +++ b/src/windows/ProfilePopout.cpp @@ -329,7 +329,7 @@ bool ProfilePopout::Layout(HWND hWnd, SIZE& fullSize) HBITMAP hnewbm = ResizeWithBackgroundColor( hdc, hbm, - ri::GetSysColorBrush(COLOR_3DFACE), + GetSysColorBrushV2(COLOR_3DFACE), hasAlpha, joinedAtIconSize, joinedAtIconSize, @@ -556,8 +556,8 @@ INT_PTR CALLBACK ProfilePopout::Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM case WM_CTLCOLORSTATIC: case WM_CTLCOLORBTN: // Windows NT 3.1 seems to send this instead of WM_CTLCOLORSTATIC for my group boxes { - SetBkColor((HDC) wParam, GetSysColor(COLOR_3DFACE)); - return (INT_PTR)ri::GetSysColorBrush(COLOR_3DFACE); + SetBkColor((HDC) wParam, GetSysColorV2(COLOR_3DFACE)); + return (INT_PTR)GetSysColorBrushV2(COLOR_3DFACE); } } diff --git a/src/windows/ProfileView.cpp b/src/windows/ProfileView.cpp index e0e443c..1693e72 100644 --- a/src/windows/ProfileView.cpp +++ b/src/windows/ProfileView.cpp @@ -107,7 +107,7 @@ void ProfileView::Paint(HDC hdc) RECT rcProfile = rect; rcProfile.right = pfpX + pfpBorderSize - ScaleByDPI(6); - FillRect(hdc, &rcProfile, ri::GetSysColorBrush(PROFILE_VIEW_COLOR)); + FillRect(hdc, &rcProfile, GetSysColorBrushV2(PROFILE_VIEW_COLOR)); if (!NT31SimplifiedInterface()) ri::DrawIconEx(hdc, pfpX - ScaleByDPI(6), pfpY - ScaleByDPI(4), g_ProfileBorderIcon, pfpBorderSizeDrawn, pfpBorderSizeDrawn, 0, NULL, DI_NORMAL | DI_COMPAT); @@ -116,8 +116,8 @@ void ProfileView::Paint(HDC hdc) DrawActivityStatus(hdc, pfpX, pfpY, activeStatus); - COLORREF clrOld = SetBkColor(hdc, GetSysColor(PROFILE_VIEW_COLOR)); - COLORREF cltOld = SetTextColor(hdc, GetSysColor(COLOR_MENUTEXT)); + COLORREF clrOld = SetBkColor(hdc, GetSysColorV2(PROFILE_VIEW_COLOR)); + COLORREF cltOld = SetTextColor(hdc, GetSysColorV2(COLOR_MENUTEXT)); HGDIOBJ objOld = SelectObject(hdc, g_AccountInfoFont); RECT rcText = rect; @@ -192,7 +192,7 @@ void ProfileView::InitializeClass() WNDCLASS& wc = g_ProfileViewClass; wc.lpszClassName = T_PROFILE_VIEW_CLASS; - wc.hbrBackground = ri::GetSysColorBrush(PROFILE_VIEW_COLOR); + wc.hbrBackground = GetSysColorBrushV2(PROFILE_VIEW_COLOR); wc.style = 0; wc.hCursor = LoadCursor(0, IDC_ARROW); wc.lpfnWndProc = ProfileView::WndProc; diff --git a/src/windows/QuickSwitcher.cpp b/src/windows/QuickSwitcher.cpp index 97b2c01..a89777a 100644 --- a/src/windows/QuickSwitcher.cpp +++ b/src/windows/QuickSwitcher.cpp @@ -297,16 +297,16 @@ LRESULT QuickSwitcher::HandleCustomDraw(HWND hWnd, NMLVCUSTOMDRAW* pInfo) int sta = ListView_GetItemState(hList, idx, LVIS_SELECTED); if (sta & LVIS_SELECTED) { - pInfo->clrTextBk = GetSysColor(COLOR_HIGHLIGHT); - pInfo->clrText = GetSysColor(COLOR_HIGHLIGHTTEXT); + pInfo->clrTextBk = GetSysColorV2(COLOR_HIGHLIGHT); + pInfo->clrText = GetSysColorV2(COLOR_HIGHLIGHTTEXT); } else if (pInfo->iSubItem == COL_CATEGORY_NAME) { - pInfo->clrTextBk = GetSysColor(COLOR_WINDOW); - pInfo->clrText = GetSysColor(COLOR_GRAYTEXT); + pInfo->clrTextBk = GetSysColorV2(COLOR_WINDOW); + pInfo->clrText = GetSysColorV2(COLOR_GRAYTEXT); } else { - pInfo->clrTextBk = GetSysColor(COLOR_WINDOW); - pInfo->clrText = GetSysColor(COLOR_MENUTEXT); + pInfo->clrTextBk = GetSysColorV2(COLOR_WINDOW); + pInfo->clrText = GetSysColorV2(COLOR_MENUTEXT); } return CDRF_NEWFONT; diff --git a/src/windows/RoleList.cpp b/src/windows/RoleList.cpp index 3b5f6c9..db878c1 100644 --- a/src/windows/RoleList.cpp +++ b/src/windows/RoleList.cpp @@ -122,10 +122,10 @@ void RoleList::DrawRole(HDC hdc, RoleItem* role) ri::DrawEdge(hdc, &rect, BDR_RAISEDINNER, BF_RECT | BF_MIDDLE | BF_ADJUST); case MS_FLAT: case MS_IMAGE: - oldBkColor = SetBkColor(hdc, GetSysColor(COLOR_3DFACE)); + oldBkColor = SetBkColor(hdc, GetSysColorV2(COLOR_3DFACE)); break; case MS_FLATBR: - oldBkColor = SetBkColor(hdc, GetSysColor(COLOR_WINDOW)); + oldBkColor = SetBkColor(hdc, GetSysColorV2(COLOR_WINDOW)); break; case MS_GRADIENT: oldBkMode = SetBkMode(hdc, TRANSPARENT); @@ -150,7 +150,7 @@ void RoleList::DrawRole(HDC hdc, RoleItem* role) DrawShinyRoleColor(hdc, &rcColor, cref); - COLORREF col2 = SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); + COLORREF col2 = SetTextColor(hdc, GetSysColorV2(COLOR_WINDOWTEXT)); DrawText(hdc, role->GetText(), -1, &rcText, DT_NOPREFIX | DT_VCENTER | DT_SINGLELINE | DT_CENTER); SetTextColor(hdc, col2); SelectObject(hdc, obj); @@ -235,10 +235,10 @@ LRESULT CALLBACK RoleList::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l eMessageStyle style = GetLocalSettings()->GetMessageStyle(); switch (style) { default: - SetClassLongPtr(hWnd, GCLP_HBRBACKGROUND, (LONG_PTR)ri::GetSysColorBrush(COLOR_3DFACE)); + SetClassLongPtr(hWnd, GCLP_HBRBACKGROUND, (LONG_PTR)GetSysColorBrushV2(COLOR_3DFACE)); break; case MS_FLATBR: - SetClassLongPtr(hWnd, GCLP_HBRBACKGROUND, (LONG_PTR)ri::GetSysColorBrush(COLOR_WINDOW)); + SetClassLongPtr(hWnd, GCLP_HBRBACKGROUND, (LONG_PTR)GetSysColorBrushV2(COLOR_WINDOW)); break; } break; @@ -378,7 +378,7 @@ void RoleList::InitializeClass() return; wc.lpszClassName = T_ROLE_LIST_CLASS; - wc.hbrBackground = ri::GetSysColorBrush(COLOR_3DFACE); + wc.hbrBackground = GetSysColorBrushV2(COLOR_3DFACE); wc.style = 0; wc.hCursor = LoadCursor(0, IDC_ARROW); wc.lpfnWndProc = RoleList::WndProc; diff --git a/src/windows/StatusBar.cpp b/src/windows/StatusBar.cpp index 514a49a..1f9749c 100644 --- a/src/windows/StatusBar.cpp +++ b/src/windows/StatusBar.cpp @@ -221,7 +221,7 @@ void StatusBar::DrawItem(LPDRAWITEMSTRUCT lpDIS) int mode = SetBkMode(hdc, TRANSPARENT); HGDIOBJ gdiObjOld = SelectObject(hdc, g_TypingBoldFont); - COLORREF textOld = SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); + COLORREF textOld = SetTextColor(hdc, GetSysColorV2(COLOR_WINDOWTEXT)); m_typing_status_rect = rc; diff --git a/src/windows/TextInterface_Win32.cpp b/src/windows/TextInterface_Win32.cpp index ff7072a..85e03da 100644 --- a/src/windows/TextInterface_Win32.cpp +++ b/src/windows/TextInterface_Win32.cpp @@ -239,7 +239,7 @@ void MdDrawString(DrawingContext* context, const Rect& rect, const String& str, setColorBG = true; } if (styleFlags & (WORD_CODE | WORD_MLCODE)) { - oldColorBG = SetBkColor(context->m_hdc, context->InvertIfNeeded(GetSysColor(COLOR_WINDOW))); + oldColorBG = SetBkColor(context->m_hdc, context->InvertIfNeeded(GetSysColorV2(COLOR_WINDOW))); setColorBG = true; flags |= DT_WORDBREAK | DT_EDITCONTROL; } @@ -254,7 +254,7 @@ void MdDrawString(DrawingContext* context, const Rect& rect, const String& str, RECT rc2 = rc; rc2.left -= ScaleByDPI(SIZE_QUOTE_INDENT); rc2.right = rc2.left + ScaleByDPI(3); - FillRect(hdc, &rc2, ri::GetSysColorBrush(COLOR_SCROLLBAR)); + FillRect(hdc, &rc2, GetSysColorBrushV2(COLOR_SCROLLBAR)); } // prevent italics that overflow the rect from being clipped @@ -285,12 +285,12 @@ void MdDrawCodeBackground(DrawingContext* context, const Rect& rect) RECT rc = RectToNative(rect); if (context->m_bInvertTextColor) { - COLORREF old = ri::SetDCBrushColor(context->m_hdc, context->InvertIfNeeded(GetSysColor(COLOR_WINDOW))); + COLORREF old = ri::SetDCBrushColor(context->m_hdc, context->InvertIfNeeded(GetSysColorV2(COLOR_WINDOW))); FillRect(context->m_hdc, &rc, ri::GetDCBrush()); ri::SetDCBrushColor(context->m_hdc, old); } else { - FillRect(context->m_hdc, &rc, ri::GetSysColorBrush(COLOR_WINDOW)); + FillRect(context->m_hdc, &rc, GetSysColorBrushV2(COLOR_WINDOW)); } ri::DrawEdge(context->m_hdc, &rc, BDR_SUNKEN, BF_RECT); @@ -304,12 +304,12 @@ void MdDrawForwardBackground(DrawingContext* context, const Rect& rect) rc.left = rc.right - ScaleByDPI(3); if (context->m_bInvertTextColor) { - COLORREF old = ri::SetDCBrushColor(context->m_hdc, context->InvertIfNeeded(GetSysColor(COLOR_GRAYTEXT))); + COLORREF old = ri::SetDCBrushColor(context->m_hdc, context->InvertIfNeeded(GetSysColorV2(COLOR_GRAYTEXT))); FillRect(context->m_hdc, &rc, ri::GetDCBrush()); ri::SetDCBrushColor(context->m_hdc, old); } else { - FillRect(context->m_hdc, &rc, ri::GetSysColorBrush(COLOR_GRAYTEXT)); + FillRect(context->m_hdc, &rc, GetSysColorBrushV2(COLOR_GRAYTEXT)); } } diff --git a/src/windows/WinUtils.cpp b/src/windows/WinUtils.cpp index 035f8ee..73df293 100644 --- a/src/windows/WinUtils.cpp +++ b/src/windows/WinUtils.cpp @@ -604,12 +604,12 @@ void FillGradient(HDC hdc, const LPRECT lpRect, int sci1, int sci2, bool vertica sci1 = COLOR_INACTIVECAPTION; } if (ri::HaveMsImg()) { - COLORREF c1 = GetSysColor(sci1); - COLORREF c2 = GetSysColor(sci2); + COLORREF c1 = GetSysColorV2(sci1); + COLORREF c2 = GetSysColorV2(sci2); FillGradientColors(hdc, lpRect, c1, c2, vertical); } else { - HBRUSH hbr = ri::GetSysColorBrush(sci1); + HBRUSH hbr = GetSysColorBrushV2(sci1); FillRect(hdc, lpRect, hbr); } } @@ -1521,7 +1521,7 @@ bool IsColorDark(COLORREF cr) bool IsTextColorDark() { - return IsColorDark(GetSysColor(COLOR_CAPTIONTEXT)); + return IsColorDark(GetSysColorV2(COLOR_CAPTIONTEXT)); } std::map m_bMostlyBlack; @@ -1767,7 +1767,7 @@ const COLORREF s_DarkModeColors[] = { RGB(255,255,255), // COLOR_HIGHLIGHTTEXT RGB(60,60,60), // COLOR_BTNFACE RGB(20,20,20), // COLOR_BTNSHADOW - RGB(64,64,64), // COLOR_GRAYTEXT + RGB(96,96,96), // COLOR_GRAYTEXT RGB(255,255,255), // COLOR_BTNTEXT RGB(128,128,128), // COLOR_INACTIVECAPTIONTEXT RGB(80,80,80), // COLOR_BTNHIGHLIGHT @@ -1794,12 +1794,12 @@ COLORREF GetSysColorV2(int nIndex) HBRUSH GetSysColorBrushV2(int nIndex) { if (!IsDarkModeEnabled()) - return GetSysColorBrush(nIndex); + return ri::GetSysColorBrush(nIndex); if (nIndex < 0 || nIndex >= 31) { // fallback, but this usage is WRONG! DbgPrintW("bad index %d used in GetSysColorBrushV2", nIndex); - return GetSysColorBrush(nIndex); + return ri::GetSysColorBrush(nIndex); } static HBRUSH brushes[31]; From 5c90c457076dbb31ff9ad40d210a86bf1b6e698d Mon Sep 17 00:00:00 2001 From: iProgramInCpp Date: Sun, 26 Jul 2026 21:31:25 +0300 Subject: [PATCH 03/14] channel view is dark mode compatible now --- src/windows/ChannelView.cpp | 40 ++++++++++++++++++++++------------ src/windows/ChannelViewOld.cpp | 10 +++++++++ src/windows/GuildLister.cpp | 2 +- src/windows/Main.cpp | 6 +++++ src/windows/MemberListOld.cpp | 9 ++++++++ src/windows/WinUtils.hpp | 8 ++++--- 6 files changed, 57 insertions(+), 18 deletions(-) diff --git a/src/windows/ChannelView.cpp b/src/windows/ChannelView.cpp index 2f81e49..419c362 100644 --- a/src/windows/ChannelView.cpp +++ b/src/windows/ChannelView.cpp @@ -85,6 +85,11 @@ bool ChannelView::InitTreeView() SetWindowFont(hwndTV, g_MessageTextFont, TRUE); + if (IsDarkModeEnabled()) { + TreeView_SetBkColor(m_treeHwnd, GetSysColorV2(COLOR_WINDOW)); + TreeView_SetTextColor(m_treeHwnd, GetSysColorV2(COLOR_WINDOWTEXT)); + } + return TRUE; } @@ -109,6 +114,11 @@ bool ChannelView::InitListView() SetWindowFont(m_listHwnd, g_MessageTextFont, TRUE); + if (IsDarkModeEnabled()) { + TreeView_SetBkColor(m_listHwnd, GetSysColorV2(COLOR_WINDOW)); + TreeView_SetTextColor(m_listHwnd, GetSysColorV2(COLOR_WINDOWTEXT)); + } + return TRUE; } @@ -494,6 +504,8 @@ ChannelView* ChannelView::Create(HWND hwnd, LPRECT rect) view = NULL; } + view->SetMode(false); + return view; } @@ -806,20 +818,20 @@ LRESULT ChannelView::ListWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPa switch (uMsg) { - case WM_DESTROY: - { - SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)NULL); - SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)pView->m_origListWndProc); - pView->m_listHwnd = NULL; - break; - } - case WM_MOUSELEAVE: - { - int oldItem = pView->m_hotItem; - pView->m_hotItem = -1; - ListView_RedrawItems(hWnd, oldItem, oldItem); - break; - } + case WM_DESTROY: + { + SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)NULL); + SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)pView->m_origListWndProc); + pView->m_listHwnd = NULL; + break; + } + case WM_MOUSELEAVE: + { + int oldItem = pView->m_hotItem; + pView->m_hotItem = -1; + ListView_RedrawItems(hWnd, oldItem, oldItem); + break; + } } return CallWindowProc(pView->m_origListWndProc, hWnd, uMsg, wParam, lParam); diff --git a/src/windows/ChannelViewOld.cpp b/src/windows/ChannelViewOld.cpp index ce137d7..2222506 100644 --- a/src/windows/ChannelViewOld.cpp +++ b/src/windows/ChannelViewOld.cpp @@ -251,6 +251,16 @@ LRESULT ChannelViewOld::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar GetDiscordInstance()->OnSelectChannel(sf); break; } + + case WM_CTLCOLORLISTBOX: + { + HDC hdc = (HDC)wParam; + + SetBkColor(hdc, GetSysColorV2(COLOR_WINDOW)); + SetTextColor(hdc, GetSysColorV2(COLOR_WINDOWTEXT)); + + return (LRESULT) GetSysColorBrushV2(COLOR_WINDOW); + } } return DefWindowProc( hWnd, uMsg, wParam, lParam ); diff --git a/src/windows/GuildLister.cpp b/src/windows/GuildLister.cpp index e8e9a49..e67f07c 100644 --- a/src/windows/GuildLister.cpp +++ b/src/windows/GuildLister.cpp @@ -536,7 +536,7 @@ void GuildLister::DrawServerIcon(HDC hdc, HBITMAP hicon, int& y, RECT& rect, Sno HGDIOBJ oldBrush, oldPen; oldBrush = SelectObject(hdc, GetSysColorBrushV2(COLOR_BTNSHADOW)); - oldPen = SelectObject(hdc, GetStockObject(BLACK_PEN)); + oldPen = SelectObject(hdc, IsDarkModeEnabled() ? GetStockObject(WHITE_PEN) : GetStockObject(BLACK_PEN)); if (currentFolder == (id & ~BIT_FOLDER)) { RoundRect(hdc, rcProfile.left + 1, rcProfile.top + 1, rcProfile.right - 1, rcProfile.top - 1 + pfpBorderSize + amount, 10, 10); diff --git a/src/windows/Main.cpp b/src/windows/Main.cpp index a49b5d0..6cb762c 100644 --- a/src/windows/Main.cpp +++ b/src/windows/Main.cpp @@ -2012,6 +2012,12 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLin pSettings->SetUseDoubleBuffering(false); } + if (IsDarkModeEnabled()) + { + // disable theming, as classic controls are easier to theme + //ri::SetThemeAppProperties(ri_STAP_ALLOW_NONCLIENT); + } + SetUserScale(GetLocalSettings()->GetUserScale()); int wndWidth = 0, wndHeight = 0; diff --git a/src/windows/MemberListOld.cpp b/src/windows/MemberListOld.cpp index cb7ea17..2f39e50 100644 --- a/src/windows/MemberListOld.cpp +++ b/src/windows/MemberListOld.cpp @@ -198,6 +198,15 @@ LRESULT MemberListOld::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara MoveWindow(pList->m_listHwnd, 0, 0, wWidth, wHeight, TRUE); break; } + + case WM_CTLCOLORLISTBOX: { + HDC hdc = (HDC)wParam; + + SetBkColor(hdc, GetSysColorV2(COLOR_WINDOW)); + SetTextColor(hdc, GetSysColorV2(COLOR_WINDOWTEXT)); + + return (LRESULT)GetSysColorBrushV2(COLOR_WINDOW); + } } return DefWindowProc(hWnd, uMsg, wParam, lParam); diff --git a/src/windows/WinUtils.hpp b/src/windows/WinUtils.hpp index b200649..b8dbb58 100644 --- a/src/windows/WinUtils.hpp +++ b/src/windows/WinUtils.hpp @@ -20,9 +20,10 @@ #define DMCDF_WS2_32 0x0040 #define DMCDF_OLE32 0x0080 #define DMCDF_COMCTL32 0x0100 -#define DMCDF_ALL 0x01FF -#define DMCDF_NODLGEX 0x0200 -#define DMCDF_NODRIEX 0x0400 +#define DMCDF_UXTHEME 0x0200 +#define DMCDF_ALL 0x03FF +#define DMCDF_NODLGEX 0x0400 +#define DMCDF_NODRIEX 0x0800 #ifdef UNICODE #define WAsnprintf _snwprintf @@ -150,6 +151,7 @@ COLORREF LerpColor(COLORREF a, COLORREF b, int progMul, int progDiv); bool IsColorDark(COLORREF cr); bool IsTextColorDark(); bool IsIconMostlyBlack(HICON hic); +bool IsDarkModeEnabled(); COLORREF GetSysColorV2(int nIndex); HBRUSH GetSysColorBrushV2(int nIndex); From bbea13ddc1fbdf4c619728a5b0cd44cc90797fdc Mon Sep 17 00:00:00 2001 From: iProgramInCpp Date: Sun, 26 Jul 2026 21:34:17 +0300 Subject: [PATCH 04/14] member list and message editor too --- src/windows/MemberList.cpp | 5 +++++ src/windows/MessageEditor.cpp | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/src/windows/MemberList.cpp b/src/windows/MemberList.cpp index 809b6bb..4d39f25 100644 --- a/src/windows/MemberList.cpp +++ b/src/windows/MemberList.cpp @@ -270,6 +270,11 @@ void MemberList::Initialize() ListView_InsertColumn(m_listHwnd, 0, &col); SetWindowFont(m_listHwnd, g_MessageTextFont, TRUE); + + if (IsDarkModeEnabled()) { + ListView_SetBkColor(m_listHwnd, GetSysColorV2(COLOR_WINDOW)); + ListView_SetTextColor(m_listHwnd, GetSysColorV2(COLOR_WINDOWTEXT)); + } } LRESULT MemberList::ListWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) diff --git a/src/windows/MessageEditor.cpp b/src/windows/MessageEditor.cpp index 59f2872..e569891 100644 --- a/src/windows/MessageEditor.cpp +++ b/src/windows/MessageEditor.cpp @@ -874,6 +874,15 @@ LRESULT MessageEditor::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara SetBkColor((HDC) wParam, GetSysColorV2(COLOR_3DFACE)); return (LRESULT)GetSysColorBrushV2(COLOR_3DFACE); } + case WM_CTLCOLOREDIT: + { + HDC hdc = (HDC)wParam; + + SetTextColor(hdc, GetSysColorV2(COLOR_WINDOWTEXT)); + SetBkColor(hdc, GetSysColorV2(COLOR_WINDOW)); + + return (LRESULT) GetSysColorBrushV2(COLOR_WINDOW); + } } return DefWindowProc(hWnd, uMsg, wParam, lParam); From ec0a8a3644ebc7b021775cc4754499f1d2280df2 Mon Sep 17 00:00:00 2001 From: iProgramInCpp Date: Sun, 26 Jul 2026 21:46:10 +0300 Subject: [PATCH 05/14] profile popout now also dark mode --- src/windows/ProfilePopout.cpp | 23 +++++++++++++++++++++-- src/windows/StatusBar.cpp | 4 ++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/windows/ProfilePopout.cpp b/src/windows/ProfilePopout.cpp index a87913b..ecf4282 100644 --- a/src/windows/ProfilePopout.cpp +++ b/src/windows/ProfilePopout.cpp @@ -465,7 +465,11 @@ void ProfilePopout::Paint(HWND hWnd, HDC hdc) RECT rect = {}; GetClientRect(hWnd, &rect); - ri::DrawEdge(hdc, &rect, EDGE_RAISED, BF_RECT | BF_MIDDLE); + int edgeFlags = BF_RECT | BF_MIDDLE; + if (IsDarkModeEnabled()) + edgeFlags &= ~BF_MIDDLE; + + ri::DrawEdge(hdc, &rect, EDGE_RAISED, edgeFlags); } void ProfilePopout::FlushNote() @@ -513,6 +517,14 @@ INT_PTR CALLBACK ProfilePopout::Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM case WM_INITDIALOG: case WM_UPDATEPROFILEPOPOUT: { + if (IsDarkModeEnabled()) { + ri::SetWindowTheme(GetDlgItem(hWnd, IDC_MEMBERSINCEGROUP), L" ", L" "); + ri::SetWindowTheme(GetDlgItem(hWnd, IDC_ROLE_GROUP), L" ", L" "); + ri::SetWindowTheme(GetDlgItem(hWnd, IDC_NOTE_GROUP), L" ", L" "); + ri::SetWindowTheme(GetDlgItem(hWnd, IDC_MESSAGE_GROUP), L" ", L" "); + ri::SetWindowTheme(GetDlgItem(hWnd, IDC_ABOUTME_GROUP), L" ", L" "); + } + m_size = {}; BOOL res = Layout(hWnd, m_size); if (!res) { @@ -547,8 +559,14 @@ INT_PTR CALLBACK ProfilePopout::Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM case WM_CTLCOLOREDIT: // Windows NT 3.1 seems to send this intead of WM_CTLCOLORSTATIC for my disabled text boxes // If the window is disabled, set the background color below - if (IsWindowEnabled((HWND)lParam)) + if (IsWindowEnabled((HWND)lParam)) { + if (IsDarkModeEnabled()) { + SetTextColor((HDC)wParam, GetSysColorV2(COLOR_WINDOWTEXT)); + SetBkColor((HDC)wParam, GetSysColorV2(COLOR_WINDOW)); + return (INT_PTR)GetSysColorBrushV2(COLOR_WINDOW); + } break; + } // fall through case WM_CTLCOLOR: @@ -556,6 +574,7 @@ INT_PTR CALLBACK ProfilePopout::Proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM case WM_CTLCOLORSTATIC: case WM_CTLCOLORBTN: // Windows NT 3.1 seems to send this instead of WM_CTLCOLORSTATIC for my group boxes { + SetTextColor((HDC) wParam, GetSysColorV2(COLOR_WINDOWTEXT)); SetBkColor((HDC) wParam, GetSysColorV2(COLOR_3DFACE)); return (INT_PTR)GetSysColorBrushV2(COLOR_3DFACE); } diff --git a/src/windows/StatusBar.cpp b/src/windows/StatusBar.cpp index 1f9749c..fdeeb78 100644 --- a/src/windows/StatusBar.cpp +++ b/src/windows/StatusBar.cpp @@ -41,6 +41,10 @@ StatusBar* StatusBar::Create(HWND hParent) SetWindowFont(pBar->m_hwnd, g_MessageTextFont, TRUE); SetWindowLongPtr(pBar->m_hwnd, GWLP_USERDATA, (LONG_PTR) pBar); + + if (IsDarkModeEnabled()) + SendMessage(pBar->m_hwnd, SB_SETBKCOLOR, 0, GetSysColorV2(COLOR_3DFACE)); + return pBar; } From e4b30e54c0be1abc3a86b248ba0679145d1dc2ae Mon Sep 17 00:00:00 2001 From: iProgramInCpp Date: Sun, 26 Jul 2026 22:21:13 +0300 Subject: [PATCH 06/14] dark status bar --- src/windows/StatusBar.cpp | 48 +++++++++++++++++++++++++++++++++++++-- src/windows/StatusBar.hpp | 3 +++ 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/src/windows/StatusBar.cpp b/src/windows/StatusBar.cpp index fdeeb78..cf5f891 100644 --- a/src/windows/StatusBar.cpp +++ b/src/windows/StatusBar.cpp @@ -42,8 +42,10 @@ StatusBar* StatusBar::Create(HWND hParent) SetWindowFont(pBar->m_hwnd, g_MessageTextFont, TRUE); SetWindowLongPtr(pBar->m_hwnd, GWLP_USERDATA, (LONG_PTR) pBar); - if (IsDarkModeEnabled()) - SendMessage(pBar->m_hwnd, SB_SETBKCOLOR, 0, GetSysColorV2(COLOR_3DFACE)); + if (IsDarkModeEnabled()) { + ri::SetWindowTheme(pBar->m_hwnd, L" ", L" "); + SendMessage(pBar->m_hwnd, SB_SETBKCOLOR, 0, (LPARAM) GetSysColorV2(COLOR_3DFACE)); + } return pBar; } @@ -192,6 +194,21 @@ void StatusBar::OnAnimationTick() void StatusBar::UpdateCharacterCounter(int nChars, int nCharsMax) { + if (IsDarkModeEnabled()) { + if (!nChars) { + if (m_charCountStr) + free(m_charCountStr); + m_charCountStr = NULL; + } + else { + std::string text = std::to_string(nChars) + "/" + std::to_string(nCharsMax); + LPTSTR tstr = ConvertCppStringToTString(text); + m_charCountStr = tstr; + } + SendMessage(m_hwnd, SB_SETTEXT, IDP_CHRCNT | SBT_OWNERDRAW, 0); + return; + } + if (!nChars) { SendMessage(m_hwnd, SB_SETTEXT, IDP_CHRCNT, (LPARAM) TEXT("")); return; @@ -204,6 +221,33 @@ void StatusBar::UpdateCharacterCounter(int nChars, int nCharsMax) } void StatusBar::DrawItem(LPDRAWITEMSTRUCT lpDIS) +{ + switch (lpDIS->itemID) { + case IDP_TYPING: + DrawTypingItem(lpDIS); + break; + case IDP_CHRCNT: + DrawCharCountItem(lpDIS); + break; + } +} + +void StatusBar::DrawCharCountItem(LPDRAWITEMSTRUCT lpDIS) +{ + HDC hdc = lpDIS->hDC; + RECT rc = lpDIS->rcItem; + int mode = SetBkMode(hdc, TRANSPARENT); + COLORREF textOld = SetTextColor(hdc, GetSysColorV2(COLOR_WINDOWTEXT)); + + if (m_charCountStr) { + DrawText(hdc, m_charCountStr, -1, &rc, DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER); + } + + SetTextColor(hdc, textOld); + SetBkMode(hdc, mode); +} + +void StatusBar::DrawTypingItem(LPDRAWITEMSTRUCT lpDIS) { // this is the only owner drawn item assert(lpDIS->itemID == IDP_TYPING); diff --git a/src/windows/StatusBar.hpp b/src/windows/StatusBar.hpp index 671e08e..aaa41a5 100644 --- a/src/windows/StatusBar.hpp +++ b/src/windows/StatusBar.hpp @@ -36,6 +36,8 @@ class StatusBar int GetNextExpiryTime(); void OnExpiryTick(); void OnAnimationTick(); + void DrawTypingItem(LPDRAWITEMSTRUCT lpDIS); + void DrawCharCountItem(LPDRAWITEMSTRUCT lpDIS); public: // should only be called by Main.cpp @@ -57,4 +59,5 @@ class StatusBar int m_anim_frame_number = 0; RECT m_typing_status_rect; RECT m_typing_animation_rect; + LPTSTR m_charCountStr = NULL; }; From b23b0220cadb5dcea4cc550f99f4ac4b1d923ac3 Mon Sep 17 00:00:00 2001 From: iProgramInCpp Date: Sun, 26 Jul 2026 22:28:34 +0300 Subject: [PATCH 07/14] buttons look like classic mode, which is slightly better than themed buttons IMO I'd have to ownerdraw the buttons if I wanted to make them fully dark. --- src/windows/GuildLister.cpp | 5 +++++ src/windows/MessageEditor.cpp | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/src/windows/GuildLister.cpp b/src/windows/GuildLister.cpp index e67f07c..25eec5c 100644 --- a/src/windows/GuildLister.cpp +++ b/src/windows/GuildLister.cpp @@ -1451,6 +1451,11 @@ GuildLister* GuildLister::Create(HWND hwnd, LPRECT pRect) } SetWindowPos(newThis->m_tooltip_hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + + if (IsDarkModeEnabled()) { + ri::SetWindowTheme(newThis->m_more_btn_hwnd, L" ", L" "); + ri::SetWindowTheme(newThis->m_bar_btn_hwnd, L" ", L" "); + } return newThis; } diff --git a/src/windows/MessageEditor.cpp b/src/windows/MessageEditor.cpp index e569891..06b23f3 100644 --- a/src/windows/MessageEditor.cpp +++ b/src/windows/MessageEditor.cpp @@ -1037,5 +1037,12 @@ MessageEditor* MessageEditor::Create(HWND hwnd, LPRECT pRect) newThis->m_autoComplete.SetLookup(&_AutoCompleteLookup); newThis->m_autoComplete.SetLookupContext(newThis); + if (IsDarkModeEnabled()) { + ri::SetWindowTheme(newThis->m_send_hwnd, L" ", L" "); + ri::SetWindowTheme(newThis->m_btnUpload_hwnd, L" ", L" "); + ri::SetWindowTheme(newThis->m_mentionJump_hwnd, L" ", L" "); + ri::SetWindowTheme(newThis->m_mentionCancel_hwnd, L" ", L" "); + } + return newThis; } From c0b46d7cad44e3d442715d4a4e7713d2d7b54daa Mon Sep 17 00:00:00 2001 From: iProgramInCpp Date: Sun, 26 Jul 2026 23:16:42 +0300 Subject: [PATCH 08/14] add dark mode option in settings --- src/core/config/LocalSettings.cpp | 5 +++ src/core/config/LocalSettings.hpp | 7 +++ src/resource.h | 4 ++ src/resource.rc | 72 +++++++++++++++++-------------- src/windows/Main.cpp | 8 ++++ src/windows/OptionsDialog.cpp | 5 +++ src/windows/WinUtils.cpp | 3 +- 7 files changed, 71 insertions(+), 33 deletions(-) diff --git a/src/core/config/LocalSettings.cpp b/src/core/config/LocalSettings.cpp index 095d688..1b261e9 100644 --- a/src/core/config/LocalSettings.cpp +++ b/src/core/config/LocalSettings.cpp @@ -163,6 +163,10 @@ bool LocalSettings::Load() if (j.contains("AddExtraHeaders")) m_bAddExtraHeaders = j["AddExtraHeaders"]; + + if (j.contains("EnableDarkMode")) + m_bEnableDarkMode = j["EnableDarkMode"]; + return true; } @@ -203,6 +207,7 @@ bool LocalSettings::Save() j["Use12HourTime"] = m_bUse12HourTime; j["ShowBlockedMessages"] = m_bShowBlockedMessages; j["UseDoubleBuffering"] = m_bUseDoubleBuffering; + j["EnableDarkMode"] = m_bEnableDarkMode; if (m_bSaveWindowSize) { j["WindowWidth"] = m_width; diff --git a/src/core/config/LocalSettings.hpp b/src/core/config/LocalSettings.hpp index cd4364e..d4e18be 100644 --- a/src/core/config/LocalSettings.hpp +++ b/src/core/config/LocalSettings.hpp @@ -226,6 +226,12 @@ class LocalSettings void SetUseDoubleBuffering(bool b) { m_bUseDoubleBuffering = b; } + bool EnableDarkMode() const { + return m_bEnableDarkMode; + } + void SetEnableDarkMode(bool b) { + m_bEnableDarkMode = b; + } private: std::string m_token; @@ -258,6 +264,7 @@ class LocalSettings bool m_bUse12HourTime = false; bool m_bShowBlockedMessages = false; bool m_bUseDoubleBuffering = false; + bool m_bEnableDarkMode = false; time_t m_remindUpdatesOn = 0; int m_width = 1000; int m_height = 700; diff --git a/src/resource.h b/src/resource.h index 1e54e0d..5353109 100644 --- a/src/resource.h +++ b/src/resource.h @@ -338,6 +338,9 @@ #define IDS_CONFIRM_UNPIN 776 #define IDS_CONFIRM_UNPIN_TITLE 777 #define IDS_ETA_STRING_DOWNLOADED 778 +#define IDS_FAILED_TO_LOAD_CONFIG_1 779 +#define IDS_FAILED_TO_LOAD_CONFIG_2 780 +#define IDS_FAILED_TO_LOAD_CONFIG_RECOVERED_TOKEN 781 #define IDC_OPTIONS_TABS 801 #define IDC_MY_ACCOUNT_BOX 802 #define IDC_MY_ACCOUNT_NAME 803 @@ -436,6 +439,7 @@ #define IDC_USE_12HR_TIME 897 #define IDC_ENABLE_BALLOON_NOTIFS 898 #define IDC_SHOW_BLOCKED_MESSAGES 898 +#define IDC_DARK_MODE 898 #define IDC_FLASH_TASKBAR 899 #define IDC_USE_DISCORD_SOUND 900 #define IDC_MUTE_NOTIFICATIONS 901 diff --git a/src/resource.rc b/src/resource.rc index 61d1393..60858a0 100644 --- a/src/resource.rc +++ b/src/resource.rc @@ -519,21 +519,22 @@ BEGIN "Button",BS_AUTORADIOBUTTON | WS_GROUP,12,18,236,10 CONTROL "Compact: Fit more messages on screen at one time. #IRC",IDC_APPEARANCE_COMPACT, "Button",BS_AUTORADIOBUTTON,12,30,236,10 - GROUPBOX "Message List Style",IDC_MSTYLE_BOX,6,105,248,29 - LTEXT "Message theme:",IDC_STATIC,12,116,53,13,SS_CENTERIMAGE - PUSHBUTTON "Change...",IDC_ACTIVE_IMAGE_BROWSE,198,146,50,14 - EDITTEXT IDC_ACTIVE_IMAGE_EDIT,53,146,135,14,ES_AUTOHSCROLL | ES_READONLY - LTEXT "Image:",IDC_STATIC,12,146,41,14,SS_CENTERIMAGE - COMBOBOX IDC_MESSAGE_STYLE,73,116,175,128,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + GROUPBOX "Message List Style",IDC_MSTYLE_BOX,6,120,248,29 + LTEXT "Message theme:",IDC_STATIC,12,131,53,13,SS_CENTERIMAGE + PUSHBUTTON "Change...",IDC_ACTIVE_IMAGE_BROWSE,198,161,50,14 + EDITTEXT IDC_ACTIVE_IMAGE_EDIT,53,161,135,14,ES_AUTOHSCROLL | ES_READONLY + LTEXT "Image:",IDC_STATIC,12,161,41,14,SS_CENTERIMAGE + COMBOBOX IDC_MESSAGE_STYLE,73,131,175,128,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP CONTROL "Compact member list",IDC_COMPACT_MEMBER_LIST,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,60,236,10 - COMBOBOX IDC_COMBO_ALIGNMENT,53,164,195,78,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Aligned to:",IDC_STATIC,12,164,41,12,SS_CENTERIMAGE - GROUPBOX "Message List Watermark",IDC_STATIC,6,135,248,48 - GROUPBOX "User Interface",IDC_STATIC,6,48,248,56 - LTEXT "Size of UI elements:",IDC_STATIC,12,86,68,12,SS_CENTERIMAGE - COMBOBOX IDC_COMBO_GUI_SCALE,80,86,168,159,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_ALIGNMENT,53,179,195,78,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Aligned to:",IDC_STATIC,12,179,41,12,SS_CENTERIMAGE + GROUPBOX "Message List Watermark",IDC_STATIC,6,150,248,48 + GROUPBOX "User Interface",IDC_STATIC,6,48,248,69 + LTEXT "Size of UI elements:",IDC_STATIC,12,100,68,12,SS_CENTERIMAGE + COMBOBOX IDC_COMBO_GUI_SCALE,80,100,168,159,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP CONTROL "Double-buffer drawing (reduces flicker but uses more memory)",IDC_DOUBLE_BUFFERING, "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,74,236,10 + CONTROL "Enable dark mode",IDC_DARK_MODE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,88,236,10 END IDD_DIALOG_PROFILE_POPOUT DIALOGEX 0, 0, 126, 134 @@ -869,19 +870,19 @@ BEGIN LISTBOX IDC_GUILD_LIST,7,19,271,158,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP END -IDD_DIALOG_PREFERENCES_ND DIALOG 0, 0, 231, 308 +IDD_DIALOG_PREFERENCES_ND DIALOG 0, 0, 269, 294 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Preferences" FONT 8, "MS Shell Dlg" BEGIN - PUSHBUTTON "Done",IDOK,174,287,50,14 - GROUPBOX "My Account",IDC_STATIC,7,7,218,36 - GROUPBOX "Appearance",IDC_STATIC,7,45,218,77 + PUSHBUTTON "Done",IDOK,212,273,50,14 + GROUPBOX "My Account",IDC_STATIC,7,7,255,36 + GROUPBOX "Appearance",IDC_STATIC,7,46,255,87 LTEXT "Static",IDC_MY_ACCOUNT_NAME,52,17,135,8 LTEXT "Username:",IDC_STATIC,12,17,36,8 LTEXT "*****@*****.***",IDC_EMAIL_DISPLAY,52,29,114,8 LTEXT "Email:",IDC_STATIC,12,29,20,8 - PUSHBUTTON "Reveal",IDC_REVEALEMAIL,169,26,50,14 + PUSHBUTTON "Reveal",IDC_REVEALEMAIL,208,26,50,14 CONTROL "Cozy",IDC_APPEARANCE_COZY,"Button",BS_AUTORADIOBUTTON,80,56,32,10 CONTROL "Compact",IDC_APPEARANCE_COMPACT,"Button",BS_AUTORADIOBUTTON,114,56,44,10 COMBOBOX IDC_MESSAGE_STYLE,80,70,137,30,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP @@ -892,24 +893,25 @@ BEGIN PUSHBUTTON "Change...",IDC_ACTIVE_IMAGE_BROWSE,169,86,50,14 LTEXT "Aligned to:",IDC_STATIC,12,105,65,8 COMBOBOX IDC_COMBO_ALIGNMENT,80,104,137,30,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP - GROUPBOX "Chat",IDC_STATIC,7,123,218,76 + GROUPBOX "Chat",IDC_STATIC,7,134,255,52 CONTROL "Disable markdown formatting",IDC_DISABLE_FORMATTING, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,134,205,10 + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,147,107,10 CONTROL "Display images when uploaded directly to Discord",IDC_IMAGES_WHEN_UPLOADED, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,147,205,10 + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,151,147,104,17 CONTROL "Display images when posted as links in chat",IDC_IMAGES_WHEN_EMBEDDED, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,160,205,10 + "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,151,165,104,19 CONTROL "Show embeds and preview links in chat",IDC_SHOW_EMBEDS, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,173,205,10 - GROUPBOX "Window",IDC_STATIC,7,200,218,38 - CONTROL "Save window size",IDC_SAVE_WINDOW_SIZE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,211,203,10 - CONTROL "Start maximized",IDC_START_MAXIMIZED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,224,203,10 - GROUPBOX "Check for updates",IDC_STATIC,7,240,218,44 + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,160,137,10 + GROUPBOX "Window",IDC_STATIC,7,186,255,38 + CONTROL "Save window size",IDC_SAVE_WINDOW_SIZE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,197,203,10 + CONTROL "Start maximized",IDC_START_MAXIMIZED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,210,203,10 + GROUPBOX "Check for updates",IDC_STATIC,7,226,255,44 CONTROL "Check for updates using the GitHub API",IDC_CHECK_UPDATES, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,251,203,10 - LTEXT "iProgramInCpp cannot see your IP address through the update service.",IDC_STATIC,12,263,204,17 - LTEXT "Changes apply automatically.",IDC_STATIC,7,289,163,8 - CONTROL "Use 12-hour time",IDC_USE_12HR_TIME,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,186,205,10 + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,237,203,10 + LTEXT "iProgramInCpp cannot see your IP address through the update service.",IDC_STATIC,12,249,204,17 + LTEXT "Changes apply automatically.",IDC_STATIC,7,275,163,8 + CONTROL "Use 12-hour time",IDC_USE_12HR_TIME,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,173,136,10 + CONTROL "Enable dark mode",IDC_DARK_MODE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,119,136,10 END @@ -1148,9 +1150,9 @@ BEGIN IDD_DIALOG_PREFERENCES_ND, DIALOG BEGIN LEFTMARGIN, 7 - RIGHTMARGIN, 224 + RIGHTMARGIN, 262 TOPMARGIN, 7 - BOTTOMMARGIN, 301 + BOTTOMMARGIN, 287 END END #endif // APSTUDIO_INVOKED @@ -1717,6 +1719,12 @@ BEGIN IDS_CONFIRM_UNPIN "You sure you want to remove this pinned message?\n\n%s (%s)\n\n%s" IDS_CONFIRM_UNPIN_TITLE "Discord Messenger - Unpin Message" IDS_ETA_STRING_DOWNLOADED "(%s (%s downloaded)" + IDS_FAILED_TO_LOAD_CONFIG_1 + "Discord Messenger failed to load your configuration. You will need to re-insert your Discord token.\n\nTechnical details:\n" + IDS_FAILED_TO_LOAD_CONFIG_2 + "\n\nThe corrupted settings file is located at:\n" + IDS_FAILED_TO_LOAD_CONFIG_RECOVERED_TOKEN + "Discord Messenger failed to load your configuration. A Discord token was successfully recovered from the corrupted config file, and will be used to attempt to log in, but it might be wrong.\n\nTechnical details:\n" END #endif // English (United States) resources diff --git a/src/windows/Main.cpp b/src/windows/Main.cpp index 6cb762c..a32afc4 100644 --- a/src/windows/Main.cpp +++ b/src/windows/Main.cpp @@ -2020,6 +2020,9 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLin SetUserScale(GetLocalSettings()->GetUserScale()); + // Create a background brush. + g_backgroundBrush = GetSysColorBrushV2(COLOR_3DFACE); + int wndWidth = 0, wndHeight = 0; bool startMaximized = false; GetLocalSettings()->GetWindowSize(wndWidth, wndHeight); @@ -2215,3 +2218,8 @@ void SetHeartbeatInterval(int timeMs) g_HeartbeatTimer = SetTimer(g_Hwnd, 0, timeMs, OnHeartbeatTimer); } } + +bool IsDarkModeEnabled() +{ + return GetLocalSettings()->EnableDarkMode(); +} diff --git a/src/windows/OptionsDialog.cpp b/src/windows/OptionsDialog.cpp index 16556e2..b5f8306 100644 --- a/src/windows/OptionsDialog.cpp +++ b/src/windows/OptionsDialog.cpp @@ -160,6 +160,7 @@ void OptionsInitPage(HWND hwndDlg, int pageNum) GetSettingsManager()->GetMessageCompact() ? IDC_APPEARANCE_COMPACT : IDC_APPEARANCE_COZY ); + CheckDlgButton(hwndDlg, IDC_DARK_MODE, GetLocalSettings()->EnableDarkMode() ? BST_CHECKED : BST_UNCHECKED); CheckDlgButton(hwndDlg, IDC_DOUBLE_BUFFERING, GetLocalSettings()->UseDoubleBuffering() ? BST_CHECKED : BST_UNCHECKED); if (ShouldBlockDoubleBuffering()) { @@ -493,6 +494,10 @@ INT_PTR OptionsHandleCommand(HWND hwndParent, HWND hWnd, int pageNum, UINT uMsg, case IDC_DOUBLE_BUFFERING: GetLocalSettings()->SetUseDoubleBuffering(IsDlgButtonChecked(hWnd, IDC_DOUBLE_BUFFERING)); break; + case IDC_DARK_MODE: + GetLocalSettings()->SetEnableDarkMode(IsDlgButtonChecked(hWnd, IDC_DARK_MODE)); + SendMessage(g_Hwnd, WM_FORCERESTART, 0, 0); + break; } break; } diff --git a/src/windows/WinUtils.cpp b/src/windows/WinUtils.cpp index 73df293..0966a74 100644 --- a/src/windows/WinUtils.cpp +++ b/src/windows/WinUtils.cpp @@ -20,6 +20,7 @@ #include "TextManager.hpp" #include "ProgressDialog.hpp" #include "DoubleBufferingHelper.hpp" +#include "config/LocalSettings.hpp" #ifndef OLD_WINDOWS #include @@ -1746,7 +1747,7 @@ std::string FilterToken(const std::string& ogToken) bool IsDarkModeEnabled() { - return true;// TODO: load from LocalSettings. + return GetLocalSettings()->EnableDarkMode(); } const COLORREF s_DarkModeColors[] = { From de5766883f25ff7e82bc5617f102fa29702a925a Mon Sep 17 00:00:00 2001 From: iProgramInCpp Date: Sun, 26 Jul 2026 23:17:17 +0300 Subject: [PATCH 09/14] * Attempt to recover a broken settings file if an attempt to load it fails. --- src/windows/Frontend_Win32.cpp | 55 ------------------- src/windows/Main.cpp | 99 ++++++++++++++++++++++++++++++---- src/windows/WinUtils.cpp | 55 +++++++++++++++++++ src/windows/WinUtils.hpp | 2 + 4 files changed, 147 insertions(+), 64 deletions(-) diff --git a/src/windows/Frontend_Win32.cpp b/src/windows/Frontend_Win32.cpp index 11545d2..0fac1bd 100644 --- a/src/windows/Frontend_Win32.cpp +++ b/src/windows/Frontend_Win32.cpp @@ -603,61 +603,6 @@ bool Frontend_Win32::UseGradientByDefault() return LOWORD(GetVersion()) >= 5; } -static std::string LoadEntireFile(const std::string& fileNameUTF8) -{ - LPTSTR fileNameUTF16 = ConvertCppStringToTString(fileNameUTF8); - HANDLE handle = CreateFile(fileNameUTF16, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - free(fileNameUTF16); - - if (!handle) { - DbgPrintW("Failed to open %s: %d", fileNameUTF8.c_str(), GetLastError()); - return ""; - } - - DWORD fileSize = GetFileSize(handle, NULL); - if (fileSize > 10000000) { - DbgPrintW("Uh oh, file is too big!"); - CloseHandle(handle); - return ""; - } - - DWORD bytesRead = 0; - std::string data; - data.resize(fileSize); - ReadFile(handle, (void*) data.data(), fileSize, &bytesRead, NULL); - CloseHandle(handle); - - if (bytesRead != fileSize) { - DbgPrintW("We only read %zu bytes, out of %zu!", (size_t) bytesRead, (size_t) fileSize); - return ""; - } - - return data; -} - -static bool SaveEntireFile(const std::string& fileNameUTF8, const std::string& data) -{ - LPTSTR fileNameUTF16 = ConvertCppStringToTString(fileNameUTF8); - HANDLE handle = CreateFile(fileNameUTF16, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); - free(fileNameUTF16); - - if (!handle) { - DbgPrintW("Failed to save %s: %d", fileNameUTF8.c_str(), GetLastError()); - return false; - } - - DWORD bytesWritten = 0; - WriteFile(handle, (const void*)data.data(), (DWORD) data.size(), &bytesWritten, NULL); - CloseHandle(handle); - - if (bytesWritten != (DWORD) data.size()) { - DbgPrintW("We only wrote %zu bytes, out of %zu! Data may have been corrupted!", (size_t) bytesWritten, data.size()); - return false; - } - - return true; -} - std::string Frontend_Win32::LoadConfig() { std::string data = LoadEntireTextFile(GetBasePath() + "/settings.json"); diff --git a/src/windows/Main.cpp b/src/windows/Main.cpp index a32afc4..4e07cdf 100644 --- a/src/windows/Main.cpp +++ b/src/windows/Main.cpp @@ -1943,6 +1943,95 @@ static bool ForceSingleInstance(LPCTSTR pClassName) return false; } +static bool IsMaybeValidDiscordToken(const std::string& token) +{ + if (token.size() < 70) + return false; + + if (token.size() > 75) + return false; + + int periodCount = 0; + for (auto ch : token) + { + if (ch == '.') { + periodCount++; + } + + if (!((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || ch == '_' || ch == '\'' || ch == '.')) { + return false; + } + } + + return periodCount == 2; +} + +static std::string PerformSettingsRecoveryOperations(bool& recoveredToken) +{ + recoveredToken = false; + + std::string settingsData = GetFrontend()->LoadConfig(); + + auto pos = settingsData.find("\"Token\":\""); + if (pos != std::string::npos) { + // Find the ending part + auto pos2 = settingsData.find("\"", pos + 9); + if (pos2 == std::string::npos) { + pos2 = settingsData.size(); + } + + std::string tokenExtracted = settingsData.substr(pos + 9, pos2 - pos - 9); + if (IsMaybeValidDiscordToken(tokenExtracted)) { + GetLocalSettings()->SetToken(tokenExtracted); + recoveredToken = true; + } + } + + std::string fn = GetBasePath() + "/bad_settings_" + std::to_string(time(NULL)) + ".json"; + if (SaveEntireFile(fn, settingsData)) + return fn; + + fn = GetBasePath() + "bs" + std::to_string(time(NULL) % 1000000) + ".jso"; + if (SaveEntireFile(fn, settingsData)) + return fn; + + return ""; +} + +static void LoadSettingsIfPossible() +{ + std::string technicalDetails; + + try + { + GetLocalSettings()->Load(); + return; + } + catch (nlohmann::json::exception ex) + { + technicalDetails = "JSON exception: " + std::string(ex.what()); + } + catch (std::exception ex) + { + technicalDetails = "Unknown exception: " + std::string(ex.what()); + } + + bool recoveredToken = false; + std::string oldPath = PerformSettingsRecoveryOperations(recoveredToken); + + std::string message = TmGetString(recoveredToken ? IDS_FAILED_TO_LOAD_CONFIG_RECOVERED_TOKEN : IDS_FAILED_TO_LOAD_CONFIG_1); + message += technicalDetails; + + if (!oldPath.empty()) { + message += TmGetString(IDS_FAILED_TO_LOAD_CONFIG_2); + message += oldPath; + } + + LPTSTR tstr = ConvertToTStringAddCR(message); + MessageBox(NULL, tstr, TmGetTString(IDS_PROGRAM_NAME), MB_ICONERROR | MB_OK); + free(tstr); +} + // Blackwingcat's Extended Kernel workaround: Apparently, the custom user32.dll it uses tries // to write to the class name, which previously was part of .rodata, which is of course read-only. TCHAR g_className[64]; @@ -1977,9 +2066,6 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLin g_pFrontEnd = new Frontend_Win32; g_pHTTPClient = new NetworkerThreadManager; - // Create a background brush. - g_backgroundBrush = GetSysColorBrushV2(COLOR_3DFACE); - SetupCachePathIfNeeded(); LocalSettings* pSettings = GetLocalSettings(); @@ -1987,7 +2073,7 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR pCmdLin // Load the settings, and fix up some settings that are // actually bad to leave on on NT 3.x or NT 4 - pSettings->Load(); + LoadSettingsIfPossible(); if (LOBYTE(version) < 5 && pSettings->GetMessageStyle() == MS_GRADIENT) { @@ -2218,8 +2304,3 @@ void SetHeartbeatInterval(int timeMs) g_HeartbeatTimer = SetTimer(g_Hwnd, 0, timeMs, OnHeartbeatTimer); } } - -bool IsDarkModeEnabled() -{ - return GetLocalSettings()->EnableDarkMode(); -} diff --git a/src/windows/WinUtils.cpp b/src/windows/WinUtils.cpp index 0966a74..b214eb1 100644 --- a/src/windows/WinUtils.cpp +++ b/src/windows/WinUtils.cpp @@ -1745,6 +1745,61 @@ std::string FilterToken(const std::string& ogToken) return newToken; } +std::string LoadEntireFile(const std::string& fileNameUTF8) +{ + LPTSTR fileNameUTF16 = ConvertCppStringToTString(fileNameUTF8); + HANDLE handle = CreateFile(fileNameUTF16, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + free(fileNameUTF16); + + if (!handle) { + DbgPrintW("Failed to open %s: %d", fileNameUTF8.c_str(), GetLastError()); + return ""; + } + + DWORD fileSize = GetFileSize(handle, NULL); + if (fileSize > 10000000) { + DbgPrintW("Uh oh, file is too big!"); + CloseHandle(handle); + return ""; + } + + DWORD bytesRead = 0; + std::string data; + data.resize(fileSize); + ReadFile(handle, (void*) data.data(), fileSize, &bytesRead, NULL); + CloseHandle(handle); + + if (bytesRead != fileSize) { + DbgPrintW("We only read %zu bytes, out of %zu!", (size_t) bytesRead, (size_t) fileSize); + return ""; + } + + return data; +} + +bool SaveEntireFile(const std::string& fileNameUTF8, const std::string& data) +{ + LPTSTR fileNameUTF16 = ConvertCppStringToTString(fileNameUTF8); + HANDLE handle = CreateFile(fileNameUTF16, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + free(fileNameUTF16); + + if (!handle) { + DbgPrintW("Failed to save %s: %d", fileNameUTF8.c_str(), GetLastError()); + return false; + } + + DWORD bytesWritten = 0; + WriteFile(handle, (const void*)data.data(), (DWORD) data.size(), &bytesWritten, NULL); + CloseHandle(handle); + + if (bytesWritten != (DWORD) data.size()) { + DbgPrintW("We only wrote %zu bytes, out of %zu! Data may have been corrupted!", (size_t) bytesWritten, data.size()); + return false; + } + + return true; +} + bool IsDarkModeEnabled() { return GetLocalSettings()->EnableDarkMode(); diff --git a/src/windows/WinUtils.hpp b/src/windows/WinUtils.hpp index b8dbb58..7cc6cd4 100644 --- a/src/windows/WinUtils.hpp +++ b/src/windows/WinUtils.hpp @@ -143,6 +143,8 @@ void DbgPrintW(const char* fmt, ...); // File utils bool FileExists(const std::string& path); +std::string LoadEntireFile(const std::string& fileNameUTF8); +bool SaveEntireFile(const std::string& fileNameUTF8, const std::string& data); bool XSetProcessDPIAware(); From 0676438d714098d0dfe0c8a2ec00d647ecb9ce74 Mon Sep 17 00:00:00 2001 From: iProgramInCpp Date: Sun, 26 Jul 2026 23:23:03 +0300 Subject: [PATCH 10/14] fix in MessageEditor --- src/windows/MessageEditor.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/windows/MessageEditor.cpp b/src/windows/MessageEditor.cpp index 06b23f3..9ec91fa 100644 --- a/src/windows/MessageEditor.cpp +++ b/src/windows/MessageEditor.cpp @@ -870,6 +870,8 @@ LRESULT MessageEditor::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara { if ((HWND) lParam == pThis->m_mentionName_hwnd) SetTextColor((HDC) wParam, pThis->m_userNameColor); + else + SetTextColor((HDC) wParam, GetSysColor(COLOR_WINDOWTEXT)); SetBkColor((HDC) wParam, GetSysColorV2(COLOR_3DFACE)); return (LRESULT)GetSysColorBrushV2(COLOR_3DFACE); From 23ef1f183c0d054ad88b8b571631dcaeecefea4d Mon Sep 17 00:00:00 2001 From: iProgramInCpp Date: Sun, 26 Jul 2026 23:25:31 +0300 Subject: [PATCH 11/14] eh, this is the fix lol --- src/windows/MessageEditor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/windows/MessageEditor.cpp b/src/windows/MessageEditor.cpp index 9ec91fa..2ac66a0 100644 --- a/src/windows/MessageEditor.cpp +++ b/src/windows/MessageEditor.cpp @@ -871,7 +871,7 @@ LRESULT MessageEditor::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara if ((HWND) lParam == pThis->m_mentionName_hwnd) SetTextColor((HDC) wParam, pThis->m_userNameColor); else - SetTextColor((HDC) wParam, GetSysColor(COLOR_WINDOWTEXT)); + SetTextColor((HDC) wParam, GetSysColorV2(COLOR_WINDOWTEXT)); SetBkColor((HDC) wParam, GetSysColorV2(COLOR_3DFACE)); return (LRESULT)GetSysColorBrushV2(COLOR_3DFACE); From b7c1e6d0196d1f716032de06bca705a54ebb8850 Mon Sep 17 00:00:00 2001 From: iProgramInCpp Date: Sun, 26 Jul 2026 23:27:58 +0300 Subject: [PATCH 12/14] update mwas to fix build on actions --- deps/mwas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/mwas b/deps/mwas index 1663c31..0a12a0d 160000 --- a/deps/mwas +++ b/deps/mwas @@ -1 +1 @@ -Subproject commit 1663c311589a3391a7b33d7cd776eb752a10a971 +Subproject commit 0a12a0d619af90854e52109bb08d0c41e94c57cb From 1d5044b8178a078446590e1cabd59e83cc6823c4 Mon Sep 17 00:00:00 2001 From: iProgramInCpp Date: Mon, 27 Jul 2026 15:15:53 +0300 Subject: [PATCH 13/14] add dark mode versions of channel icons, because I can't just invert the existing ones --- res/icons/icon_channel_dark.ico | Bin 0 -> 5430 bytes res/icons/icon_channel_dark_2k.ico | Bin 0 -> 518 bytes res/icons/icon_channel_mentioned_dark.ico | Bin 0 -> 5430 bytes res/icons/icon_channel_mentioned_dark_2k.ico | Bin 0 -> 1078 bytes res/icons/icon_channel_unread_dark.ico | Bin 0 -> 5430 bytes res/icons/icon_channel_unread_dark_2k.ico | Bin 0 -> 518 bytes res/icons/icon_dm_dark.ico | Bin 0 -> 5430 bytes res/icons/icon_dm_dark_2k.ico | Bin 0 -> 518 bytes res/icons/icon_groupdm_dark.ico | Bin 0 -> 5430 bytes res/icons/icon_groupdm_dark_2k.ico | Bin 0 -> 518 bytes res/icons/icon_voice_dark.ico | Bin 0 -> 1150 bytes res/icons/icon_voice_dark_2k.ico | Bin 0 -> 198 bytes src/resource.h | 12 ++++++ src/resource.rc | 24 +++++++++++ src/windows/ChannelView.cpp | 14 +++---- src/windows/WinUtils.cpp | 42 +++++++++++++++++++ src/windows/WinUtils.hpp | 2 + vs/DiscordMessenger.vcxproj | 12 ++++++ vs/DiscordMessenger.vcxproj.filters | 36 ++++++++++++++++ 19 files changed, 135 insertions(+), 7 deletions(-) create mode 100644 res/icons/icon_channel_dark.ico create mode 100644 res/icons/icon_channel_dark_2k.ico create mode 100644 res/icons/icon_channel_mentioned_dark.ico create mode 100644 res/icons/icon_channel_mentioned_dark_2k.ico create mode 100644 res/icons/icon_channel_unread_dark.ico create mode 100644 res/icons/icon_channel_unread_dark_2k.ico create mode 100644 res/icons/icon_dm_dark.ico create mode 100644 res/icons/icon_dm_dark_2k.ico create mode 100644 res/icons/icon_groupdm_dark.ico create mode 100644 res/icons/icon_groupdm_dark_2k.ico create mode 100644 res/icons/icon_voice_dark.ico create mode 100644 res/icons/icon_voice_dark_2k.ico diff --git a/res/icons/icon_channel_dark.ico b/res/icons/icon_channel_dark.ico new file mode 100644 index 0000000000000000000000000000000000000000..e844ce1a556f9f1a94f55f5ec9473c3369c758d2 GIT binary patch literal 5430 zcmeHKJ!=$E6urp`D_A6`{VpP6Etqx#TIe6}4`?CSTiEP`putA4(8j_xh@G~|S_RZj z5ClV31T92~jc#Dg^W5FJ(A7!rVp(ff~j_WWU&4{8yoS4Lq#S$L6Btd>-J~2K1b3j;gul zt%37v!VKX)a-m@7S|@cWt(8Qha{=YEQvDv8dx4#6ovu%n`tQgsK-OY&S=X8G6UPcr zXRbK~G;djqcmZ%Puyd`Gnss$UG&&a$-v#!8F>o8;S=C(YY|YOb$0b0o#pasB^&MaY z+%Wps-0F`*cg$#+6PsIoMo;v6hiL2Z6oWRA;L`@t&n=>1>j0zAM2x+!1dr)^ri+)# zD!}ifN$`uuM8&maoN?weIMmHPlk<8%F5;OO0DAz(1HikMT)wv#uU%$S6(3N0nq0oO z7q9X6TdrM>(LoW@_u==ng5%Y4=GXI(B|d)d0ce*8B=$2&AUk0Hgk9$v3~o2orO zyVjJa-p6`)z1B5VdwzDUfGOj-G5=W3W!+|vPtfM#wDITv^^Q9GT!cx3!H68^dTl>Zgu|0dy|%TM{Agx?=^2Ch#yXUOGy{snv(UjQ9X(8yX<_V@&C zU1-my>bl;{`yVk+{snG;VB6dbe%HxbRgUoqx_`k<;d=aeo9BBo^H}Zn t+hKxUD~x*UVV9_HFB%>P+xz+zAX5e*vri)3X2o literal 0 HcmV?d00001 diff --git a/res/icons/icon_channel_dark_2k.ico b/res/icons/icon_channel_dark_2k.ico new file mode 100644 index 0000000000000000000000000000000000000000..da730369e680d68e12898ce7582c05493161ad21 GIT binary patch literal 518 zcmZ|LF$%&!5Czb`31}ml(n3rsv9z>{r?B=2-XOVwNAL$D|=3(9#xdNuW;@!y`eyYm$GXhc^CQ|c?L?SG&Tzad2c@0;9O7C8827I!IbcTSk(#X|$>lG56x*fiip~Nd5 IXV3n70?CS~jQ{`u literal 0 HcmV?d00001 diff --git a/res/icons/icon_channel_mentioned_dark.ico b/res/icons/icon_channel_mentioned_dark.ico new file mode 100644 index 0000000000000000000000000000000000000000..1f63c88dedbe8d120c71297a3b119ed39ce9716d GIT binary patch literal 5430 zcmeHLziSjx5T45kiHKZK`#V&`S~2Y%XrYyz|9}>Py@-XkK{VJ17TQ<|7D2Sql*$E* zfZ7Q{z~G6Xg(zpE7dW$iv%7OQJNw@L2*xNl@ZJ1)-^}-RZ};Vts76yXJ4^5_I=_SH z5D~RnalVN9P1Fvfh7gRn4o4l-t%YGoK4`9w< zH8b`n{a@hgYAsXu^z(lB{;|ygdVi_9r=R!yiko3i0d)b8Fm`gWOK=J@Kizd}y*W0`1WK1Q!b z6roP^eu3!Q3Q-@iVEBQEvHppm5uYg4<2KVYpJkD2r0{(rD#!@$1S^7 zWv1nFURKA&bIr@11@ZZa?_;Nn@0we-mYwH5izj=^c6hW-pxy)40k+#f=3b?z6=}L-<=PQO*2JfC4_lzmI=x7B@^SVL>Icx`zY*GA zBjLKBgP0gwaQzrtX!pQ~e$Q-^K0lMu@1$+gA3*;AfbW22%I~4n`zPP=6U^847KyA~ zL3}hlE&shsbK?v%qG!nC52CJ(e*?|{;~qUT|2}BuB-XP$@jKMD9Y^BPpVT#nW1m@` zBfpE9wgn_(eMh_-wW$RBekAWmb_b4L*W5GUX?uyp#gp1;tUm`H0r!DRKt`NvC9w~@ zpMV(0djVg6RlaWy*MkHf;k7+LB5N+6$LG0ap*4S3TvnTTTVel_et;VwSTi?+&qi5u zc^{w9w;5bC`VR}{ROJ`#>4?$)ioBk)hpPM{eLmAZn?20s=vUGS%c(Z8IdzZrhf z9?lv4X9fCI`9=Ew*Ejd>{_XcId93n6L0jC_QdH?_b literal 0 HcmV?d00001 diff --git a/res/icons/icon_channel_mentioned_dark_2k.ico b/res/icons/icon_channel_mentioned_dark_2k.ico new file mode 100644 index 0000000000000000000000000000000000000000..f8e7238673a554a801ceee8f8765d88b0600ce31 GIT binary patch literal 1078 zcmb_aOHRWu5Pd0Zx=L=~tWa+ePQaCF!~y6wxACq^u7Jd%EQ7kCQWf*wIF^fnMI|PA zGoFvfl7zcCkdvLQm%*x_`>^SsJSFOLI_Mm zdl92n1RsT@E@iy~+6nDAnq80MPDQ81M#a_P#5!5qUfGr#)HhpeII&)hWxtEfaR3fa z#3S#>yN4U#xF=o;UKtZktQFGyiKm_|?}^NlCx=|qoSgUV-gD2L<`wa+Pv2jk@ArG|x%ZyA?}-#-K!%0{ zx-5I-^P-vH}W+~vf`Jp?GX0s0m??$%kG zb)jNwTpgqM6fh06f#U#UNpZJM+k6fwTLCwh7I!(cPXH}ouc}Xr>-xp0Tc~QuNsH_H z9KOhpn#hDf9lBoV;@u^YuM;AT;%~Ixix5*E1v9$mOc{qt72tU^BRqJNBwS05HO{&R z|9ag5?BxOAF)(F7n=$6*a(|Yi{|g{Zm?I}-4O_sg1H1;xIlx!99r>CPqX20yv z+2qZI{7v&?Y=Fh2+6m6(7JNU}5PaT)^Vm$TbQ} z#($Cv$l<`ZGds*c7{H*zG23 un0f_P?5!r+R_!5Y?5h@fa@hm>H+lksx&sdE9d`6l#h$07ANEz*s literal 0 HcmV?d00001 diff --git a/res/icons/icon_dm_dark.ico b/res/icons/icon_dm_dark.ico new file mode 100644 index 0000000000000000000000000000000000000000..3f20a78de3998b7475b61ff27b54c964bb358575 GIT binary patch literal 5430 zcmeI0JBSle6oyYWk@(Ic;;YaIDk4@QHYzHDtsp9bXemAl8$qoMtcaCbC@PALf@@`C zp&*h*1x0)nDn3}zV)3~kzSkYUf0KdZFv(`u$z+Q?@Go)2GqI zKZ4Lc;hcy2&<*e4A)J845SM!a^Q#Y@z!ExGo2e67Pq?E!&fAe?_)C&FbI$gU7D34B}c zFX!G_cnVrm;u)NSRp4WXfp0b|Fw27#%t~3v)TYe+9^x2AKiX%CuoAQ%^_w=Hhz-AS zx8!%&!91*kY>Vb&0=h3i&;Cvr3u&*xC20Nv*$3!=sSwwXanvt_Wv~YHY^faGf8*NL ztJ_NsZ`#Ywz#`ZL7eM<{AJj6PSBl#L+B@p$Menr{e;tytZzNLx=Rj1eR(S@oIvbO; zpCmgB{%otIKbg3DNs7B%+TUkFEp3fmdvY`FHOXf~v=5q_JIxe!xu4)i*XBWYKMnU3 zBHSOPSy(R zMpX0P*$QzquU7Rpw@80iRbTJvZ&U8WNA&dG6YfD9Q`X<+w8K7}PN@%CZ0DV4N&K&vLLTiCC*daO%+P;W&8w~|-vXWMTVWdbv5fd5^AWcOSSCSm6gr^%qY!lQ p2?190@Z|yW_}Ma_5k$%O1~C9-;<_qi)xMWc8GYmn%G&b&wZGv!{`UX? literal 0 HcmV?d00001 diff --git a/res/icons/icon_dm_dark_2k.ico b/res/icons/icon_dm_dark_2k.ico new file mode 100644 index 0000000000000000000000000000000000000000..a265576daf7dac4f6171250265db79d35570d2f9 GIT binary patch literal 518 zcmZvZ%~6Cv5Jo@Xz!4%4PL{{b0Hg419v+y3d6E=XeW(gq4-x>552!4OB!#6G70EU96WNx{xm$C(ABhbFr`ydO4Vw!zJ>PHv@M{GA{NbdR7$iLrO{}lX>thmOW`w^4^#P{ zjLms)3M_$7Kv@p@z6n>rU{;TKXH$P4%H$&&4+U-4WCow3uY*1qfnT7NTuVpfIgIko z%zfb0A?m}57D|DBY}#JsMhx%WYSoMY6(ze3r4*r~jS;o%VeYR9@2rji#h za6Wn8eA%_xkpCv?m%%`xeX8HlyKXT&25-S0_#!L2S1yNn z@Cf_{$_gmPJ%TpRqi6VLm<2_feBC?dMljcO#5>+Im5&wWvuOW43-%3qB^(3MAKLrF zvoaI81gD5ork53h{!0A;aDBA*Y`+RKl~-_VHGkvx!^^qg6O`9LeA6Dy_06>SAdY2o zkGA9J|0)aae(+AW?=(0F-HLbg0*HJ?J%_%xvm~3)aVB~(_bhB(1RfHROH@ z{wBUbK8(g5XulK1{Ju9l!+G(Hh24+&jxNjfT-=DiswCz)IXk~My^67S%eRyGj8SZBbOS@~;pnK<9)z%!_iV}1u_D*773v-Sjd7a7+# zRV#75E(PtxZ_*nuUC~Eh@3ZT{cRp%!^33grkZ&o(cilKwMn@a%82rs%gcabKbbhh6jwx_Xr^7wq zdc>S5PRb4Zjq!(GpY?UB+`qeEGkBM{uZ+74o&ndi?3?X=%dcPLcm1A*e^PwAxi*or zsQv9$fqSl(;`%=f&as%YtbQ(b@eZNbm3)Brg;18KU7KsM7~J<|zaz~p#r4|`OTaVG zE>9YPBX~HU9q~qi{_c9IK)i!CaV~M#uW@PIUK;HyPmH7?p!5&7Vl={6@_y H@9**#;L6g6 literal 0 HcmV?d00001 diff --git a/res/icons/icon_groupdm_dark_2k.ico b/res/icons/icon_groupdm_dark_2k.ico new file mode 100644 index 0000000000000000000000000000000000000000..3f8637486e1164259a9b7f6b44123639880d9305 GIT binary patch literal 518 zcmZ9Iu}Z{15QhIGU=WVmlorQrDzUuIMiL*zM@Z+1a7jQsyF7xg;3Fj1*x6a{afR(3 z2NEIP_-~>RZs6P5nc3O-cL5JRqR6NB@B-kR#PJX>Jm7=z1&LgqxO2{mejOHnv=4)dH~Eq;EDci!~=7Wr@Vg$)Ra@R zW|(U=`#9d|jmb6n*ZU`%nL%E^;nM3Jf-_Fc7M|F7C`MIc)w8srCaH9a%t=*AesSE%B literal 0 HcmV?d00001 diff --git a/res/icons/icon_voice_dark.ico b/res/icons/icon_voice_dark.ico new file mode 100644 index 0000000000000000000000000000000000000000..ae7d1f0cd7480bcf835b5812203cabc168d3b841 GIT binary patch literal 1150 zcmbu8F-ikb5QhK7Sc<6>D+4w;K@b~3v=BUlm4&4i9$-tsoFSE+Hwd{vE)cM@5v)YC zP*9)WBr_r}F@d}Z-~MmrpLx8^?n)KEW>Z{SI&VlDlG;Ft%A}4+czL9hw16Z0%>_OA z9*6Yr`OGW&2nU|$y?MSx-xFAv*B`G^`b00imd`}qz#n+OiPd-E2EM_f3l+qS=>?oY z9_GEl5KiG8ENY1P)p2F^#d_}Dx0*S@|*;|yM!lJKwG z>7i|3kI?YFG$rBBn=d_o>HlYEEO~x$kEYAMKY#Zqd4FS{lJ6(>2%Z1^?n@ur(#yK^ Xup-q^RTJu(9DZ{=>#<&&NzDELDf)Ou literal 0 HcmV?d00001 diff --git a/res/icons/icon_voice_dark_2k.ico b/res/icons/icon_voice_dark_2k.ico new file mode 100644 index 0000000000000000000000000000000000000000..331be883925c2f65c9f48a62ffa5973f0c74f869 GIT binary patch literal 198 zcmZQzU<5(|0VXiLfq{WR42U&=SOAC>fEXkX0u5jiLNFn*|Ns9F;T>RLVEe$pz-Ph0 zAa{p>q3#V3rvb4U6oc46F_0Wc4M;5mP!9-zjQDTQ!0?lwf#KtE28M^q3=ECJKs*zO VPeL(>4HN^(fz*K1g7kp&0s!WkB&GlW literal 0 HcmV?d00001 diff --git a/src/resource.h b/src/resource.h index 5353109..fbd473d 100644 --- a/src/resource.h +++ b/src/resource.h @@ -105,6 +105,18 @@ #define IDR_LINK_CONTEXT 104 #define IDI_PROFILE_BORDER_UNREAD_2K 105 #define IDR_IMAGE_CONTEXT 105 +#define IDI_CHANNEL_DARK 106 +#define IDI_DM_DARK 107 +#define IDI_GROUPDM_DARK 108 +#define IDI_VOICE_DARK 109 +#define IDI_CHANNEL_MENTIONED_DARK 110 +#define IDI_CHANNEL_UNREAD_DARK 111 +#define IDI_CHANNEL_DARK_2K 112 +#define IDI_DM_DARK_2K 113 +#define IDI_GROUPDM_DARK_2K 114 +#define IDI_VOICE_DARK_2K 115 +#define IDI_CHANNEL_MENTIONED_DARK_2K 116 +#define IDI_CHANNEL_UNREAD_DARK_2K 117 #define IDB_TARGET 200 #define IDB_CHANNEL 201 #define IDB_CATEGORY 202 diff --git a/src/resource.rc b/src/resource.rc index 60858a0..79f2e1e 100644 --- a/src/resource.rc +++ b/src/resource.rc @@ -458,6 +458,30 @@ IDI_PROFILE_BORDER_UNREAD ICON "../res/icons/icon_profile_bor IDI_PROFILE_BORDER_UNREAD_2K ICON "../res/icons/icon_profile_border_unread_2k.ico" +IDI_CHANNEL_DARK ICON "../res/icons/icon_channel_dark.ico" + +IDI_DM_DARK ICON "../res/icons/icon_dm_dark.ico" + +IDI_GROUPDM_DARK ICON "../res/icons/icon_groupdm_dark.ico" + +IDI_VOICE_DARK ICON "../res/icons/icon_voice_dark.ico" + +IDI_CHANNEL_MENTIONED_DARK ICON "../res/icons/icon_channel_mentioned_dark.ico" + +IDI_CHANNEL_UNREAD_DARK ICON "../res/icons/icon_channel_unread_dark.ico" + +IDI_CHANNEL_DARK_2K ICON "../res/icons/icon_channel_dark_2k.ico" + +IDI_DM_DARK_2K ICON "../res/icons/icon_dm_dark_2k.ico" + +IDI_GROUPDM_DARK_2K ICON "../res/icons/icon_groupdm_dark_2k.ico" + +IDI_VOICE_DARK_2K ICON "../res/icons/icon_voice_dark_2k.ico" + +IDI_CHANNEL_MENTIONED_DARK_2K ICON "../res/icons/icon_channel_mentioned_dark_2k.ico" + +IDI_CHANNEL_UNREAD_DARK_2K ICON "../res/icons/icon_channel_unread_dark_2k.ico" + ///////////////////////////////////////////////////////////////////////////// // diff --git a/src/windows/ChannelView.cpp b/src/windows/ChannelView.cpp index 419c362..0602369 100644 --- a/src/windows/ChannelView.cpp +++ b/src/windows/ChannelView.cpp @@ -63,13 +63,13 @@ bool ChannelView::InitTreeView() // Add the open file, closed file, and document bitmaps. m_nCategoryExpandIcon = ri::ImageList_AddIcon(himl, LoadIcon(g_hInstance, MAKEINTRESOURCE(DMIC(IDI_CATEGORY_EXPAND)))); m_nCategoryCollapseIcon = ri::ImageList_AddIcon(himl, LoadIcon(g_hInstance, MAKEINTRESOURCE(DMIC(IDI_CATEGORY_COLLAPSE)))); - m_nChannelIcon = ri::ImageList_AddIcon(himl, LoadIcon(g_hInstance, MAKEINTRESOURCE(DMIC(IDI_CHANNEL)))); - m_nForumIcon = ri::ImageList_AddIcon(himl, LoadIcon(g_hInstance, MAKEINTRESOURCE(DMIC(IDI_GROUPDM)))); - m_nVoiceIcon = ri::ImageList_AddIcon(himl, LoadIcon(g_hInstance, MAKEINTRESOURCE(DMIC(IDI_VOICE)))); - m_nDmIcon = ri::ImageList_AddIcon(himl, LoadIcon(g_hInstance, MAKEINTRESOURCE(DMIC(IDI_DM)))); - m_nGroupDmIcon = ri::ImageList_AddIcon(himl, LoadIcon(g_hInstance, MAKEINTRESOURCE(DMIC(IDI_GROUPDM)))); - m_nChannelDotIcon = ri::ImageList_AddIcon(himl, LoadIcon(g_hInstance, MAKEINTRESOURCE(DMIC(IDI_CHANNEL_UNREAD)))); - m_nChannelRedIcon = ri::ImageList_AddIcon(himl, LoadIcon(g_hInstance, MAKEINTRESOURCE(DMIC(IDI_CHANNEL_MENTIONED)))); + m_nChannelIcon = ri::ImageList_AddIcon(himl, LoadIcon(g_hInstance, MAKEINTRESOURCE(DMIC(DMV(IDI_CHANNEL))))); + m_nForumIcon = ri::ImageList_AddIcon(himl, LoadIcon(g_hInstance, MAKEINTRESOURCE(DMIC(DMV(IDI_GROUPDM))))); + m_nVoiceIcon = ri::ImageList_AddIcon(himl, LoadIcon(g_hInstance, MAKEINTRESOURCE(DMIC(DMV(IDI_VOICE))))); + m_nDmIcon = ri::ImageList_AddIcon(himl, LoadIcon(g_hInstance, MAKEINTRESOURCE(DMIC(DMV(IDI_DM))))); + m_nGroupDmIcon = ri::ImageList_AddIcon(himl, LoadIcon(g_hInstance, MAKEINTRESOURCE(DMIC(DMV(IDI_GROUPDM))))); + m_nChannelDotIcon = ri::ImageList_AddIcon(himl, LoadIcon(g_hInstance, MAKEINTRESOURCE(DMIC(DMV(IDI_CHANNEL_UNREAD))))); + m_nChannelRedIcon = ri::ImageList_AddIcon(himl, LoadIcon(g_hInstance, MAKEINTRESOURCE(DMIC(DMV(IDI_CHANNEL_MENTIONED))))); // Fail if not all of the images were added. int ic = ri::ImageList_GetImageCount(himl); diff --git a/src/windows/WinUtils.cpp b/src/windows/WinUtils.cpp index b214eb1..0e4283e 100644 --- a/src/windows/WinUtils.cpp +++ b/src/windows/WinUtils.cpp @@ -1166,7 +1166,9 @@ int MapIconToOldIfNeeded(int iconID) switch (iconID) { + case IDI_CHANNEL_MENTIONED_DARK: return IDI_CHANNEL_MENTIONED_DARK_2K; case IDI_PROFILE_BORDER_UNREAD: return IDI_PROFILE_BORDER_UNREAD_2K; + case IDI_CHANNEL_UNREAD_DARK: return IDI_CHANNEL_UNREAD_DARK_2K; case IDI_PROFILE_BORDER_GOLD: return IDI_PROFILE_BORDER_GOLD_2K; case IDI_CHANNEL_MENTIONED: return IDI_CHANNEL_MENTIONED_2K; case IDI_CHANNEL_UNREAD: return IDI_CHANNEL_UNREAD_2K; @@ -1174,15 +1176,19 @@ int MapIconToOldIfNeeded(int iconID) case IDI_TYPING_FRAME1: return IDI_TYPING_FRAME1_2K; case IDI_TYPING_FRAME2: return IDI_TYPING_FRAME2_2K; case IDI_TYPING_FRAME3: return IDI_TYPING_FRAME3_2K; + case IDI_CHANNEL_DARK: return IDI_CHANNEL_DARK_2K; + case IDI_GROUPDM_DARK: return IDI_GROUPDM_DARK_2K; case IDI_NOTIFICATION: return IDI_NOTIFICATION_2K; case IDI_REPLY_PIECE: return IDI_REPLY_PIECE_2K; case IDI_SHIFT_RIGHT: return IDI_SHIFT_RIGHT_2K; case IDI_NEW_INLINE: return IDI_NEW_INLINE_2K; case IDI_SHIFT_LEFT: return IDI_SHIFT_LEFT_2K; + case IDI_VOICE_DARK: return IDI_VOICE_DARK_2K; case IDI_CATEGORY: return IDI_CATEGORY_2K; case IDI_CHANNEL: return IDI_CHANNEL_2K; case IDI_MEMBERS: return IDI_MEMBERS_2K; case IDI_GROUPDM: return IDI_GROUPDM_2K; + case IDI_DM_DARK: return IDI_DM_DARK_2K; case IDI_SERVER: return IDI_SERVER_2K; case IDI_BOOST: return IDI_BOOST_2K; case IDI_VOICE: return IDI_VOICE_2K; @@ -1200,6 +1206,42 @@ int MapIconToOldIfNeeded(int iconID) } } +int MapIconToDarkModeIfNeeded(int iconID) +{ + if (!IsDarkModeEnabled()) + return iconID; + + switch (iconID) + { + case IDI_CHANNEL: + return IDI_CHANNEL_DARK; + case IDI_VOICE: + return IDI_VOICE_DARK; + case IDI_DM: + return IDI_DM_DARK; + case IDI_GROUPDM: + return IDI_GROUPDM_DARK; + case IDI_CHANNEL_MENTIONED: + return IDI_CHANNEL_MENTIONED_DARK; + case IDI_CHANNEL_UNREAD: + return IDI_CHANNEL_UNREAD_DARK; + case IDI_CHANNEL_2K: + return IDI_CHANNEL_DARK_2K; + case IDI_VOICE_2K: + return IDI_VOICE_DARK_2K; + case IDI_DM_2K: + return IDI_DM_DARK_2K; + case IDI_GROUPDM_2K: + return IDI_GROUPDM_DARK_2K; + case IDI_CHANNEL_MENTIONED_2K: + return IDI_CHANNEL_MENTIONED_DARK_2K; + case IDI_CHANNEL_UNREAD_2K: + return IDI_CHANNEL_UNREAD_DARK_2K; + default: + return iconID; + } +} + int MapDialogToOldIfNeeded(int iid) { if (SupportsDialogEx()) diff --git a/src/windows/WinUtils.hpp b/src/windows/WinUtils.hpp index 7cc6cd4..f867268 100644 --- a/src/windows/WinUtils.hpp +++ b/src/windows/WinUtils.hpp @@ -110,6 +110,7 @@ SIZE EnsureMaximumSize(int width, int height, int maxWidth, int maxHeight); bool Supports32BitIcons(); // Really, this checks if we are using Windows 2000 or older. bool SupportsDialogEx(); // Really, this checks if we are using Windows NT 3.51 or older. int MapIconToOldIfNeeded(int iconID); +int MapIconToDarkModeIfNeeded(int iconID); int MapDialogToOldIfNeeded(int dialogID); void InitializeStatusIcons(); void DrawMentionStatus(HDC hdc, int x, int y, int mentionCount); @@ -139,6 +140,7 @@ void DbgPrintW(const char* fmt, ...); // Convenience macro #define DMIC(iid) MapIconToOldIfNeeded((iid)) +#define DMV(iid) MapIconToDarkModeIfNeeded((iid)) #define DMDI(iid) MapDialogToOldIfNeeded((iid)) // File utils diff --git a/vs/DiscordMessenger.vcxproj b/vs/DiscordMessenger.vcxproj index dc18896..e44246d 100644 --- a/vs/DiscordMessenger.vcxproj +++ b/vs/DiscordMessenger.vcxproj @@ -483,21 +483,31 @@ + + + + + + + + + + @@ -563,6 +573,8 @@ + + diff --git a/vs/DiscordMessenger.vcxproj.filters b/vs/DiscordMessenger.vcxproj.filters index 5b534b2..ee5cca2 100644 --- a/vs/DiscordMessenger.vcxproj.filters +++ b/vs/DiscordMessenger.vcxproj.filters @@ -498,6 +498,42 @@ Resource Files + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + From 94014792c61ef565d568286bbc824e808bb34f22 Mon Sep 17 00:00:00 2001 From: iProgramInCpp Date: Mon, 27 Jul 2026 15:24:08 +0300 Subject: [PATCH 14/14] DrawEdge dark mode support --- src/windows/MessageList.cpp | 6 +++--- src/windows/ProfilePopout.cpp | 7 +------ src/windows/RoleList.cpp | 2 +- src/windows/TextInterface_Win32.cpp | 2 +- src/windows/WinUtils.cpp | 17 +++++++++++++++-- src/windows/WinUtils.hpp | 1 + 6 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/windows/MessageList.cpp b/src/windows/MessageList.cpp index ae51a1f..b68e76c 100644 --- a/src/windows/MessageList.cpp +++ b/src/windows/MessageList.cpp @@ -1558,7 +1558,7 @@ void MessageList::DrawDefaultAttachment(HDC hdc, RECT& paintRect, AttachmentItem if (inView) { - ri::DrawEdge(hdc, &childAttachRect, BDR_RAISEDINNER | BDR_RAISEDOUTER, BF_RECT | BF_MIDDLE); + DrawEdgeV2(hdc, &childAttachRect, BDR_RAISEDINNER | BDR_RAISEDOUTER, BF_RECT | BF_MIDDLE); DrawText(hdc, name, -1, &textRect, DT_NOPREFIX | DT_NOCLIP); ri::DrawIconEx( hdc, @@ -2342,7 +2342,7 @@ void MessageList::DrawMessage(HDC hdc, MessageItem& item, RECT& msgRect, RECT& c bkgdColor = GetSysColorV2(COLOR_3DFACE); if (item.m_msg->m_type != MessageType::CHANNEL_HEADER) { - ri::DrawEdge(hdc, &rect2, BDR_RAISED, edgeFlags); + DrawEdgeV2(hdc, &rect2, BDR_RAISED, edgeFlags); } else if (edgeFlags & BF_MIDDLE) { FillRect(hdc, &rect2, GetSysColorBrushV2(COLOR_3DFACE)); @@ -5372,7 +5372,7 @@ void MessagePollData::Draw(HDC hdc, RECT& messageRect, MessageList* pList) rcPoll.right = rcPoll.left + m_width; rcPoll.bottom = rcPoll.top + m_height; rcPoll2 = rcPoll; - ri::DrawEdge(hdc, &rcPoll2, EDGE_RAISED, BF_RECT); + DrawEdgeV2(hdc, &rcPoll2, EDGE_RAISED, BF_RECT); rcPoll.left += borderSize; rcPoll.top += borderSize; diff --git a/src/windows/ProfilePopout.cpp b/src/windows/ProfilePopout.cpp index ecf4282..a65f53c 100644 --- a/src/windows/ProfilePopout.cpp +++ b/src/windows/ProfilePopout.cpp @@ -464,12 +464,7 @@ void ProfilePopout::Paint(HWND hWnd, HDC hdc) { RECT rect = {}; GetClientRect(hWnd, &rect); - - int edgeFlags = BF_RECT | BF_MIDDLE; - if (IsDarkModeEnabled()) - edgeFlags &= ~BF_MIDDLE; - - ri::DrawEdge(hdc, &rect, EDGE_RAISED, edgeFlags); + DrawEdgeV2(hdc, &rect, EDGE_RAISED, BF_RECT | BF_MIDDLE); } void ProfilePopout::FlushNote() diff --git a/src/windows/RoleList.cpp b/src/windows/RoleList.cpp index db878c1..d7b9fc6 100644 --- a/src/windows/RoleList.cpp +++ b/src/windows/RoleList.cpp @@ -119,7 +119,7 @@ void RoleList::DrawRole(HDC hdc, RoleItem* role) COLORREF oldBkColor = CLR_NONE; switch (style) { case MS_3DFACE: - ri::DrawEdge(hdc, &rect, BDR_RAISEDINNER, BF_RECT | BF_MIDDLE | BF_ADJUST); + DrawEdgeV2(hdc, &rect, BDR_RAISEDINNER, BF_RECT | BF_MIDDLE | BF_ADJUST); case MS_FLAT: case MS_IMAGE: oldBkColor = SetBkColor(hdc, GetSysColorV2(COLOR_3DFACE)); diff --git a/src/windows/TextInterface_Win32.cpp b/src/windows/TextInterface_Win32.cpp index 85e03da..c0fa392 100644 --- a/src/windows/TextInterface_Win32.cpp +++ b/src/windows/TextInterface_Win32.cpp @@ -293,7 +293,7 @@ void MdDrawCodeBackground(DrawingContext* context, const Rect& rect) FillRect(context->m_hdc, &rc, GetSysColorBrushV2(COLOR_WINDOW)); } - ri::DrawEdge(context->m_hdc, &rc, BDR_SUNKEN, BF_RECT); + DrawEdgeV2(context->m_hdc, &rc, BDR_SUNKEN, BF_RECT); } void MdDrawForwardBackground(DrawingContext* context, const Rect& rect) diff --git a/src/windows/WinUtils.cpp b/src/windows/WinUtils.cpp index 0e4283e..ace6d4a 100644 --- a/src/windows/WinUtils.cpp +++ b/src/windows/WinUtils.cpp @@ -1313,7 +1313,7 @@ void DrawActivityStatus(HDC hdc, int x, int y, eActiveStatus status) void DrawLoadingBox(HDC hdc, RECT rect) { - ri::DrawEdge(hdc, &rect, BDR_SUNKEN, BF_RECT); + DrawEdgeV2(hdc, &rect, BDR_SUNKEN, BF_RECT); HRGN rgn = DoubleBufferingHelper::CreateRectRgn(hdc, rect); SelectClipRgn(hdc, rgn); @@ -1329,7 +1329,7 @@ void DrawLoadingBox(HDC hdc, RECT rect) void DrawErrorBox(HDC hdc, RECT rect) { - ri::DrawEdge(hdc, &rect, BDR_SUNKEN, BF_RECT); + DrawEdgeV2(hdc, &rect, BDR_SUNKEN, BF_RECT); HRGN rgn = DoubleBufferingHelper::CreateRectRgn(hdc, rect); SelectClipRgn(hdc, rgn); @@ -1906,3 +1906,16 @@ HBRUSH GetSysColorBrushV2(int nIndex) return brushes[nIndex]; } + +BOOL DrawEdgeV2(HDC hdc, LPRECT lprect, UINT style, UINT grfFlags) +{ + if (!IsDarkModeEnabled()) + return ri::DrawEdge(hdc, lprect, style, grfFlags); + + if (grfFlags & BF_MIDDLE) { + grfFlags &= ~BF_MIDDLE; + FillRect(hdc, lprect, GetSysColorBrushV2(COLOR_3DFACE)); + } + + return ri::DrawEdge(hdc, lprect, style, grfFlags); +} diff --git a/src/windows/WinUtils.hpp b/src/windows/WinUtils.hpp index f867268..057af2b 100644 --- a/src/windows/WinUtils.hpp +++ b/src/windows/WinUtils.hpp @@ -158,6 +158,7 @@ bool IsIconMostlyBlack(HICON hic); bool IsDarkModeEnabled(); COLORREF GetSysColorV2(int nIndex); HBRUSH GetSysColorBrushV2(int nIndex); +BOOL DrawEdgeV2(HDC hdc, LPRECT lprect, UINT style, UINT grfFlags); #define IsColorLight(cr) (!IsColorDark(cr)) #define IsTextColorLight() (!IsTextColorDark())