Skip to content

Commit

Permalink
Add svg icon support
Browse files Browse the repository at this point in the history
  • Loading branch information
ysc3839 committed Jul 14, 2020
1 parent ef17a6a commit 1944083
Show file tree
Hide file tree
Showing 9 changed files with 137 additions and 9 deletions.
34 changes: 33 additions & 1 deletion AudioPlaybackConnector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ void SetupFlyout();
void SetupMenu();
winrt::fire_and_forget ConnectDevice(DevicePicker, std::wstring_view);
void SetupDevicePicker();
void SetupSvgIcon();
void UpdateNotifyIcon();

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
Expand Down Expand Up @@ -49,7 +50,6 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
.lpszClassName = L"AudioPlaybackConnector",
.hIconSm = wcex.hIcon
};
g_nid.hIcon = wcex.hIcon;

RegisterClassExW(&wcex);

Expand All @@ -70,6 +70,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
SetupFlyout();
SetupMenu();
SetupDevicePicker();
SetupSvgIcon();

g_nid.hWnd = g_niid.hWnd = g_hWnd;
wcscpy_s(g_nid.szTip, _(L"AudioPlaybackConnector"));
Expand Down Expand Up @@ -118,6 +119,12 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
Shell_NotifyIconW(NIM_DELETE, &g_nid);
PostQuitMessage(0);
break;
case WM_SETTINGCHANGE:
if (lParam && CompareStringOrdinal(reinterpret_cast<LPCWCH>(lParam), -1, L"ImmersiveColorSet", -1, TRUE) == CSTR_EQUAL)
{
UpdateNotifyIcon();
}
break;
case WM_NOTIFYICON:
switch (LOWORD(lParam))
{
Expand Down Expand Up @@ -403,8 +410,33 @@ void SetupDevicePicker()
});
}

void SetupSvgIcon()
{
auto hRes = FindResourceW(g_hInst, MAKEINTRESOURCEW(1), L"SVG");
FAIL_FAST_LAST_ERROR_IF_NULL(hRes);

auto size = SizeofResource(g_hInst, hRes);
FAIL_FAST_LAST_ERROR_IF(size == 0);

auto hResData = LoadResource(g_hInst, hRes);
FAIL_FAST_LAST_ERROR_IF_NULL(hResData);

auto svgData = reinterpret_cast<const char*>(LockResource(hResData));
FAIL_FAST_IF_NULL_ALLOC(svgData);

const std::string_view svg(svgData, size);
const int width = GetSystemMetrics(SM_CXSMICON), height = GetSystemMetrics(SM_CYSMICON);

g_hIconLight = SvgTohIcon(svg, width, height, { 0, 0, 0, 1 });
g_hIconDark = SvgTohIcon(svg, width, height, { 1, 1, 1, 1 });
}

void UpdateNotifyIcon()
{
DWORD value = 0, cbValue = sizeof(value);
LOG_IF_WIN32_ERROR(RegGetValueW(HKEY_CURRENT_USER, LR"(Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)", L"AppsUseLightTheme", RRF_RT_REG_DWORD, nullptr, &value, &cbValue));
g_nid.hIcon = value != 0 ? g_hIconLight : g_hIconDark;

if (!Shell_NotifyIconW(NIM_MODIFY, &g_nid))
{
if (Shell_NotifyIconW(NIM_ADD, &g_nid))
Expand Down
3 changes: 3 additions & 0 deletions AudioPlaybackConnector.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ MenuFlyout g_xamlMenu = nullptr;
FocusState g_menuFocusState = FocusState::Unfocused;
DevicePicker g_devicePicker = nullptr;
std::unordered_map<std::wstring, std::pair<DeviceInformation, AudioPlaybackConnection>> g_audioPlaybackConnections;
HICON g_hIconLight = nullptr;
HICON g_hIconDark = nullptr;
NOTIFYICONDATAW g_nid = {
.cbSize = sizeof(g_nid),
.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP | NIF_SHOWTIP,
Expand All @@ -39,3 +41,4 @@ std::vector<std::wstring> g_lastDevices;
#include "Util.hpp"
#include "I18n.hpp"
#include "SettingsUtil.hpp"
#include "Direct2DSvg.hpp"
Binary file modified AudioPlaybackConnector.ico
Binary file not shown.
8 changes: 8 additions & 0 deletions AudioPlaybackConnector.rc
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,14 @@ BEGIN
END
END


/////////////////////////////////////////////////////////////////////////////
//
// SVG
//

1 SVG "AudioPlaybackConnector.svg"

#endif // Neutral resources
/////////////////////////////////////////////////////////////////////////////

Expand Down
1 change: 1 addition & 0 deletions AudioPlaybackConnector.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 9 additions & 8 deletions AudioPlaybackConnector.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<MinimumRequiredVersion>10</MinimumRequiredVersion>
<AdditionalDependencies>comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
Expand All @@ -190,7 +190,7 @@
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<MinimumRequiredVersion>10</MinimumRequiredVersion>
<AdditionalDependencies>comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
Expand All @@ -214,7 +214,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<MinimumRequiredVersion>10</MinimumRequiredVersion>
<AdditionalOptions>/PDBALTPATH:%_PDB% %(AdditionalOptions)</AdditionalOptions>
<AdditionalDependencies>ucrt.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>ucrt.lib;comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<IgnoreSpecificDefaultLibraries>libucrt.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
</Link>
</ItemDefinitionGroup>
Expand All @@ -239,7 +239,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<MinimumRequiredVersion>10</MinimumRequiredVersion>
<AdditionalOptions>/PDBALTPATH:%_PDB% %(AdditionalOptions)</AdditionalOptions>
<AdditionalDependencies>ucrt.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>ucrt.lib;comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<IgnoreSpecificDefaultLibraries>libucrt.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
</Link>
</ItemDefinitionGroup>
Expand All @@ -258,7 +258,7 @@
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<MinimumRequiredVersion>10</MinimumRequiredVersion>
<AdditionalDependencies>comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
Expand All @@ -276,7 +276,7 @@
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<MinimumRequiredVersion>10</MinimumRequiredVersion>
<AdditionalDependencies>comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
Expand All @@ -300,7 +300,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<MinimumRequiredVersion>10</MinimumRequiredVersion>
<AdditionalOptions>/PDBALTPATH:%_PDB% %(AdditionalOptions)</AdditionalOptions>
<AdditionalDependencies>ucrt.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>ucrt.lib;comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<IgnoreSpecificDefaultLibraries>libucrt.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
</Link>
</ItemDefinitionGroup>
Expand All @@ -325,12 +325,13 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<MinimumRequiredVersion>10</MinimumRequiredVersion>
<AdditionalOptions>/PDBALTPATH:%_PDB% %(AdditionalOptions)</AdditionalOptions>
<AdditionalDependencies>ucrt.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>ucrt.lib;comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<IgnoreSpecificDefaultLibraries>libucrt.lib;%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="AudioPlaybackConnector.h" />
<ClInclude Include="Direct2DSvg.hpp" />
<ClInclude Include="pch.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="SettingsUtil.hpp" />
Expand Down
3 changes: 3 additions & 0 deletions AudioPlaybackConnector.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@
<ClInclude Include="Util.hpp">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Direct2DSvg.hpp">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="AudioPlaybackConnector.cpp">
Expand Down
78 changes: 78 additions & 0 deletions Direct2DSvg.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#pragma once

void DrawSvgTohDC(std::string_view svg, HDC hdc, LONG width, LONG height, const D2D1_COLOR_F& color)
{
winrt::com_ptr<ID2D1Factory> factory;
winrt::check_hresult(D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, factory.put()));

D2D1_RENDER_TARGET_PROPERTIES props = {
.type = D2D1_RENDER_TARGET_TYPE_DEFAULT,
.pixelFormat = {
.format = DXGI_FORMAT_B8G8R8A8_UNORM,
.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED
},
.dpiX = 0, .dpiY = 0,
.usage = D2D1_RENDER_TARGET_USAGE_NONE,
.minLevel = D2D1_FEATURE_LEVEL_DEFAULT
};
winrt::com_ptr<ID2D1DCRenderTarget> gdiDCRT;
winrt::check_hresult(factory->CreateDCRenderTarget(&props, gdiDCRT.put()));

RECT rect = { 0, 0, width, height };
winrt::check_hresult(gdiDCRT->BindDC(hdc, &rect));

auto istream = SHCreateMemStream(reinterpret_cast<const BYTE*>(svg.data()), static_cast<UINT>(svg.size()));
THROW_IF_NULL_ALLOC(istream);
winrt::com_ptr<IStream> stream(istream, winrt::take_ownership_from_abi);

auto dc = gdiDCRT.as<ID2D1DeviceContext5>();
dc->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);

winrt::com_ptr<ID2D1SvgDocument> svgDoc;
winrt::check_hresult(dc->CreateSvgDocument(stream.get(), { static_cast<FLOAT>(width), static_cast<FLOAT>(height) }, svgDoc.put()));

winrt::com_ptr<ID2D1SvgElement> svgRoot;
svgDoc->GetRoot(svgRoot.put());
svgRoot->SetAttributeValue(L"fill", color);

dc->BeginDraw();
dc->DrawSvgDocument(svgDoc.get());
dc->EndDraw();
}

auto CreateDIB(HDC hdc, LONG width, LONG height, WORD bitCount)
{
BITMAPINFO bmi = { .bmiHeader = {
.biSize = sizeof(BITMAPINFOHEADER),
.biWidth = width,
.biHeight = height,
.biPlanes = 1,
.biBitCount = bitCount,
.biCompression = BI_RGB,
} };
return wil::unique_hbitmap(CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, nullptr, nullptr, 0));
}

HICON SvgTohIcon(std::string_view svg, LONG width, LONG height, const D2D1_COLOR_F& color)
{
wil::unique_hdc hdc(CreateCompatibleDC(nullptr));
THROW_IF_NULL_ALLOC(hdc);

auto hBitmap = CreateDIB(hdc.get(), width, height, 32);
THROW_IF_NULL_ALLOC(hBitmap);
auto hBitmapMask = CreateDIB(hdc.get(), width, height, 1);
THROW_IF_NULL_ALLOC(hBitmapMask);

auto select = wil::SelectObject(hdc.get(), hBitmap.get());
DrawSvgTohDC(svg, hdc.get(), width, height, color);

ICONINFO iconInfo = {
.fIcon = TRUE,
.hbmMask = hBitmapMask.get(),
.hbmColor = hBitmap.get()
};
HICON hIcon = CreateIconIndirect(&iconInfo);
THROW_LAST_ERROR_IF_NULL(hIcon);

return hIcon;
}
2 changes: 2 additions & 0 deletions pch.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
#include <commctrl.h>
#include <shellapi.h>
#include <shobjidl_core.h>
#include <d2d1_3.h>
#include <shlwapi.h>

// C++ RunTime Header Files
#include <cstdlib>
Expand Down

0 comments on commit 1944083

Please sign in to comment.