Fix typos
[TortoiseGit.git] / src / Utils / TaskbarUUID.cpp
blob1a6a1a3dc9d0d552918fc57c4a01b6f52bff6466
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2013-2020, 2023 - TortoiseGit
4 // Copyright (C) 2011-2012, 2016 - TortoiseSVN
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "stdafx.h"
21 #include "TaskbarUUID.h"
22 #include "registry.h"
23 #include "CmdLineParser.h"
24 #include "LoadIconEx.h"
25 #include <Shobjidl.h>
26 #include "SmartHandle.h"
27 #include <atlbase.h>
28 #pragma warning(push)
29 #pragma warning(disable: 4458)
30 #include <GdiPlus.h>
31 #pragma warning(pop)
32 #pragma comment(lib, "gdiplus.lib")
34 #define APPID (L"TGIT.TGIT.1")
36 void SetTaskIDPerUUID()
38 using SetCurrentProcessExplicitAppUserModelIDFN = HRESULT(STDAPICALLTYPE)(PCWSTR AppID);
39 CAutoLibrary hShell = AtlLoadSystemLibraryUsingFullPath(L"shell32.dll");
40 if (hShell)
42 auto pfnSetCurrentProcessExplicitAppUserModelID = reinterpret_cast<SetCurrentProcessExplicitAppUserModelIDFN*>(GetProcAddress(hShell, "SetCurrentProcessExplicitAppUserModelID"));
43 if (pfnSetCurrentProcessExplicitAppUserModelID)
45 std::wstring id = GetTaskIDPerUUID();
46 pfnSetCurrentProcessExplicitAppUserModelID(id.c_str());
51 std::wstring GetTaskIDPerUUID(LPCWSTR uuid /*= nullptr */)
53 CRegStdDWORD r = CRegStdDWORD(L"Software\\TortoiseGit\\GroupTaskbarIconsPerRepo", 3);
54 std::wstring id = APPID;
55 if ((r < 2)||(r == 3))
57 wchar_t buf[MAX_PATH] = {0};
58 GetModuleFileName(nullptr, buf, _countof(buf));
59 std::wstring n = buf;
60 n = n.substr(n.find_last_of('\\'));
61 id += n;
64 if (r >= 3)
66 if (uuid)
68 id += uuid;
70 else
72 CCmdLineParser parser(GetCommandLine());
73 if (parser.HasVal(L"groupuuid"))
75 id += parser.GetVal(L"groupuuid");
79 return id;
82 #ifdef __AFXWIN_H__
83 extern CString g_sGroupingUUID;
84 extern CString g_sGroupingIcon;
85 extern bool g_bGroupingRemoveIcon;
86 #endif
88 void SetUUIDOverlayIcon( HWND hWnd )
90 if (!CRegStdDWORD(L"Software\\TortoiseGit\\GroupTaskbarIconsPerRepo", 3))
91 return;
93 if (!CRegStdDWORD(L"Software\\TortoiseGit\\GroupTaskbarIconsPerRepoOverlay", TRUE))
94 return;
96 std::wstring uuid;
97 std::wstring sicon;
98 bool bRemoveicon = false;
99 #ifdef __AFXWIN_H__
100 uuid = g_sGroupingUUID;
101 sicon = g_sGroupingIcon;
102 bRemoveicon = g_bGroupingRemoveIcon;
103 #else
104 CCmdLineParser parser(GetCommandLine());
105 if (parser.HasVal(L"groupuuid"))
106 uuid = parser.GetVal(L"groupuuid");
107 #endif
108 if (uuid.empty())
109 return;
111 CComPtr<ITaskbarList3> pTaskbarInterface;
112 if (FAILED(pTaskbarInterface.CoCreateInstance(CLSID_TaskbarList, nullptr, CLSCTX_INPROC_SERVER)))
113 return;
115 int foundUUIDIndex = 0;
118 wchar_t buf[MAX_PATH] = { 0 };
119 swprintf_s(buf, L"%s%d", L"Software\\TortoiseGit\\LastUsedUUIDsForGrouping\\", foundUUIDIndex);
120 CRegStdString r = CRegStdString(buf);
121 std::wstring sr = r;
122 if (sr.empty())
124 r = uuid + (sicon.empty() ? L"" : (L";" + sicon));
125 break;
127 size_t sep = sr.find(L';');
128 std::wstring olduuid = sep != std::wstring::npos ? sr.substr(0, sep) : sr;
129 if (olduuid.compare(uuid) == 0)
131 if (bRemoveicon)
132 r = uuid; // reset icon path in registry
133 else if (!sicon.empty())
134 r = uuid + (sicon.empty() ? L"" : (L";" + sicon));
135 else
136 sicon = sep != std::wstring::npos ? sr.substr(sep + 1) : L"";
137 break;
139 foundUUIDIndex++;
140 } while (foundUUIDIndex < 20);
141 if (foundUUIDIndex >= 20)
143 CRegStdString r = CRegStdString(L"Software\\TortoiseGit\\LastUsedUUIDsForGrouping\\1");
144 r.removeKey();
147 int iconWidth = GetSystemMetrics(SM_CXSMICON);
148 int iconHeight = GetSystemMetrics(SM_CYSMICON);
150 CAutoIcon icon;
151 if (!sicon.empty())
153 if (sicon.size() >= 4 && !_wcsicmp(sicon.substr(sicon.size() - 4).c_str(), L".ico"))
154 icon = LoadIconEx(nullptr, sicon.c_str(), iconWidth, iconHeight);
155 else
157 ULONG_PTR gdiplusToken = 0;
158 Gdiplus::GdiplusStartupInput gdiplusStartupInput;
159 GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, nullptr);
160 if (gdiplusToken)
163 auto pBitmap = std::make_unique<Gdiplus::Bitmap>(sicon.c_str(), FALSE);
164 if (pBitmap->GetLastStatus() == Gdiplus::Status::Ok)
165 pBitmap->GetHICON(icon.GetPointer());
167 Gdiplus::GdiplusShutdown(gdiplusToken);
172 if (!icon)
174 DWORD colors[6] = { 0x80FF0000, 0x80FFFF00, 0x8000FF00, 0x800000FF, 0x80000000, 0x8000FFFF };
176 // AND mask - monochrome - determines which pixels get drawn
177 auto AND = std::make_unique<BYTE[]>(iconWidth * iconWidth);
178 for (int i = 0; i < iconWidth * iconWidth; ++i)
179 AND[i] = 0xff;
181 // XOR mask - 32bpp ARGB - determines the pixel values
182 auto XOR = std::make_unique<DWORD[]>(iconWidth * iconWidth);
183 for (int i = 0; i < iconWidth * iconWidth; ++i)
184 XOR[i] = colors[foundUUIDIndex % 6];
186 icon = ::CreateIcon(nullptr, iconWidth, iconHeight, 1, 32, AND.get(), reinterpret_cast<BYTE*>(XOR.get()));
188 pTaskbarInterface->SetOverlayIcon(hWnd, icon, uuid.c_str());