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.
21 #include "TaskbarUUID.h"
23 #include "CmdLineParser.h"
24 #include "LoadIconEx.h"
26 #include "SmartHandle.h"
29 #pragma warning(disable: 4458)
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");
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
));
60 n
= n
.substr(n
.find_last_of('\\'));
72 CCmdLineParser
parser(GetCommandLine());
73 if (parser
.HasVal(L
"groupuuid"))
75 id
+= parser
.GetVal(L
"groupuuid");
83 extern CString g_sGroupingUUID
;
84 extern CString g_sGroupingIcon
;
85 extern bool g_bGroupingRemoveIcon
;
88 void SetUUIDOverlayIcon( HWND hWnd
)
90 if (!CRegStdDWORD(L
"Software\\TortoiseGit\\GroupTaskbarIconsPerRepo", 3))
93 if (!CRegStdDWORD(L
"Software\\TortoiseGit\\GroupTaskbarIconsPerRepoOverlay", TRUE
))
98 bool bRemoveicon
= false;
100 uuid
= g_sGroupingUUID
;
101 sicon
= g_sGroupingIcon
;
102 bRemoveicon
= g_bGroupingRemoveIcon
;
104 CCmdLineParser
parser(GetCommandLine());
105 if (parser
.HasVal(L
"groupuuid"))
106 uuid
= parser
.GetVal(L
"groupuuid");
111 CComPtr
<ITaskbarList3
> pTaskbarInterface
;
112 if (FAILED(pTaskbarInterface
.CoCreateInstance(CLSID_TaskbarList
, nullptr, CLSCTX_INPROC_SERVER
)))
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
);
124 r
= uuid
+ (sicon
.empty() ? L
"" : (L
";" + sicon
));
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)
132 r
= uuid
; // reset icon path in registry
133 else if (!sicon
.empty())
134 r
= uuid
+ (sicon
.empty() ? L
"" : (L
";" + sicon
));
136 sicon
= sep
!= std::wstring::npos
? sr
.substr(sep
+ 1) : L
"";
140 } while (foundUUIDIndex
< 20);
141 if (foundUUIDIndex
>= 20)
143 CRegStdString r
= CRegStdString(L
"Software\\TortoiseGit\\LastUsedUUIDsForGrouping\\1");
147 int iconWidth
= GetSystemMetrics(SM_CXSMICON
);
148 int iconHeight
= GetSystemMetrics(SM_CYSMICON
);
153 if (sicon
.size() >= 4 && !_wcsicmp(sicon
.substr(sicon
.size() - 4).c_str(), L
".ico"))
154 icon
= LoadIconEx(nullptr, sicon
.c_str(), iconWidth
, iconHeight
);
157 ULONG_PTR gdiplusToken
= 0;
158 Gdiplus::GdiplusStartupInput gdiplusStartupInput
;
159 GdiplusStartup(&gdiplusToken
, &gdiplusStartupInput
, nullptr);
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
);
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
)
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());