Get rid of magic numbers
[TortoiseGit.git] / src / Utils / TaskbarUUID.cpp
blob75a1999ad7968cf7e1015fd7fb9be4c026726f17
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2013-2014, 2016-2018 - 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 #pragma once
21 #include "stdafx.h"
22 #include "TaskbarUUID.h"
23 #include "registry.h"
24 #include "CmdLineParser.h"
25 #include "LoadIconEx.h"
26 #include <Shobjidl.h>
27 #include "SmartHandle.h"
28 #include <atlbase.h>
29 #pragma warning(push)
30 #pragma warning(disable: 4458)
31 #include <GdiPlus.h>
32 #pragma warning(pop)
33 #pragma comment(lib, "gdiplus.lib")
35 #define APPID (L"TGIT.TGIT.1")
37 void SetTaskIDPerUUID()
39 typedef HRESULT STDAPICALLTYPE SetCurrentProcessExplicitAppUserModelIDFN(PCWSTR AppID);
40 CAutoLibrary hShell = AtlLoadSystemLibraryUsingFullPath(L"shell32.dll");
41 if (hShell)
43 SetCurrentProcessExplicitAppUserModelIDFN *pfnSetCurrentProcessExplicitAppUserModelID = (SetCurrentProcessExplicitAppUserModelIDFN*)GetProcAddress(hShell, "SetCurrentProcessExplicitAppUserModelID");
44 if (pfnSetCurrentProcessExplicitAppUserModelID)
46 std::wstring id = GetTaskIDPerUUID();
47 pfnSetCurrentProcessExplicitAppUserModelID(id.c_str());
52 std::wstring GetTaskIDPerUUID(LPCTSTR uuid /*= nullptr */)
54 CRegStdDWORD r = CRegStdDWORD(L"Software\\TortoiseGit\\GroupTaskbarIconsPerRepo", 3);
55 std::wstring id = APPID;
56 if ((r < 2)||(r == 3))
58 wchar_t buf[MAX_PATH] = {0};
59 GetModuleFileName(nullptr, buf, _countof(buf));
60 std::wstring n = buf;
61 n = n.substr(n.find_last_of('\\'));
62 id += n;
65 if (r >= 3)
67 if (uuid)
69 id += uuid;
71 else
73 CCmdLineParser parser(GetCommandLine());
74 if (parser.HasVal(L"groupuuid"))
76 id += parser.GetVal(L"groupuuid");
80 return id;
83 #ifdef __AFXWIN_H__
84 extern CString g_sGroupingUUID;
85 extern CString g_sGroupingIcon;
86 extern bool g_bGroupingRemoveIcon;
87 #endif
89 void SetUUIDOverlayIcon( HWND hWnd )
91 if (!CRegStdDWORD(L"Software\\TortoiseGit\\GroupTaskbarIconsPerRepo", 3))
92 return;
94 if (!CRegStdDWORD(L"Software\\TortoiseGit\\GroupTaskbarIconsPerRepoOverlay", TRUE))
95 return;
97 std::wstring uuid;
98 std::wstring sicon;
99 bool bRemoveicon = false;
100 #ifdef __AFXWIN_H__
101 uuid = g_sGroupingUUID;
102 sicon = g_sGroupingIcon;
103 bRemoveicon = g_bGroupingRemoveIcon;
104 #else
105 CCmdLineParser parser(GetCommandLine());
106 if (parser.HasVal(L"groupuuid"))
107 uuid = parser.GetVal(L"groupuuid");
108 #endif
109 if (uuid.empty())
110 return;
112 CComPtr<ITaskbarList3> pTaskbarInterface;
113 if (FAILED(pTaskbarInterface.CoCreateInstance(CLSID_TaskbarList, nullptr, CLSCTX_INPROC_SERVER)))
114 return;
116 int foundUUIDIndex = 0;
119 wchar_t buf[MAX_PATH] = { 0 };
120 swprintf_s(buf, L"%s%d", L"Software\\TortoiseGit\\LastUsedUUIDsForGrouping\\", foundUUIDIndex);
121 CRegStdString r = CRegStdString(buf);
122 std::wstring sr = r;
123 if (sr.empty())
125 r = uuid + (sicon.empty() ? L"" : (L";" + sicon));
126 break;
128 size_t sep = sr.find(L';');
129 std::wstring olduuid = sep != std::wstring::npos ? sr.substr(0, sep) : sr;
130 if (olduuid.compare(uuid) == 0)
132 if (bRemoveicon)
133 r = uuid; // reset icon path in registry
134 else if (!sicon.empty())
135 r = uuid + (sicon.empty() ? L"" : (L";" + sicon));
136 else
137 sicon = sep != std::wstring::npos ? sr.substr(sep + 1) : L"";
138 break;
140 foundUUIDIndex++;
141 } while (foundUUIDIndex < 20);
142 if (foundUUIDIndex >= 20)
144 CRegStdString r = CRegStdString(L"Software\\TortoiseGit\\LastUsedUUIDsForGrouping\\1");
145 r.removeKey();
148 int iconWidth = GetSystemMetrics(SM_CXSMICON);
149 int iconHeight = GetSystemMetrics(SM_CYSMICON);
151 HICON icon = nullptr;
152 if (!sicon.empty())
154 if (sicon.size() >= 4 && !_wcsicmp(sicon.substr(sicon.size() - 4).c_str(), L".ico"))
155 icon = LoadIconEx(nullptr, sicon.c_str(), iconWidth, iconHeight);
156 else
158 ULONG_PTR gdiplusToken = 0;
159 Gdiplus::GdiplusStartupInput gdiplusStartupInput;
160 GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, nullptr);
161 if (gdiplusToken)
164 auto pBitmap = std::make_unique<Gdiplus::Bitmap>(sicon.c_str(), FALSE);
165 if (pBitmap->GetLastStatus() == Gdiplus::Status::Ok)
166 pBitmap->GetHICON(&icon);
168 Gdiplus::GdiplusShutdown(gdiplusToken);
173 if (!icon)
175 DWORD colors[6] = { 0x80FF0000, 0x80FFFF00, 0x8000FF00, 0x800000FF, 0x80000000, 0x8000FFFF };
177 // AND mask - monochrome - determines which pixels get drawn
178 auto AND = std::make_unique<BYTE[]>(iconWidth * iconWidth);
179 for (int i = 0; i < iconWidth * iconWidth; ++i)
180 AND[i] = 0xff;
182 // XOR mask - 32bpp ARGB - determines the pixel values
183 auto XOR = std::make_unique<DWORD[]>(iconWidth * iconWidth);
184 for (int i = 0; i < iconWidth * iconWidth; ++i)
185 XOR[i] = colors[foundUUIDIndex % 6];
187 icon = ::CreateIcon(nullptr, iconWidth, iconHeight, 1, 32, AND.get(), (BYTE*)XOR.get());
189 pTaskbarInterface->SetOverlayIcon(hWnd, icon, uuid.c_str());
190 DestroyIcon(icon);