A simple, small calculator placed discreetly near the Windows Taskbar or anywhere on the screen
0

Configure Feed

Select the types of activity you want to include in your feed.

feat: tray icon, owner window, single-instance guard, About/Exit

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

authored by

Marco Maroni
Claude Opus 4.8 (1M context)
and committed by
Tangled
(Jul 15, 2026, 1:16 PM +0300) a2360d0f 3e555ba0

+188 -3
+30
AboutDialog.cpp
··· 1 + #include "stdafx.h" 2 + #include <commctrl.h> 3 + 4 + INT_PTR CALLBACK AboutDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) 5 + { 6 + switch (uMsg) { 7 + case WM_INITDIALOG: 8 + return TRUE; 9 + case WM_NOTIFY: 10 + switch (((LPNMHDR)lParam)->code) { 11 + case NM_CLICK: 12 + case NM_RETURN: { 13 + PNMLINK p = (PNMLINK)lParam; 14 + if (p->item.iLink == 0) 15 + ShellExecuteW(NULL, L"open", p->item.szUrl, NULL, NULL, SW_SHOW); 16 + break; 17 + } 18 + } 19 + break; 20 + case WM_COMMAND: 21 + switch (LOWORD(wParam)) { 22 + case IDOK: 23 + case IDCANCEL: 24 + EndDialog(hwndDlg, TRUE); 25 + return TRUE; 26 + } 27 + break; 28 + } 29 + return FALSE; 30 + }
+93 -3
App.cpp
··· 1 1 #include "stdafx.h" 2 + #include <commctrl.h> 3 + #include <winrt/Windows.Foundation.h> 4 + #include "TrayIcon.h" 5 + #include "StartupManager.h" 6 + #include "resource.h" 2 7 3 - int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int) 8 + enum { IDM_SHOWHIDE = 1, IDM_STARTUP = 2, IDM_ABOUT = 3, IDM_EXIT = 4 }; 9 + static const UINT WM_TRAY_CALLBACK = WM_APP + 1; 10 + static const UINT TRAY_ICON_ID = 1; 11 + 12 + UINT g_wmTaskbarCreated = 0; 13 + static TrayIcon g_tray; 14 + 15 + INT_PTR CALLBACK AboutDialogProc(HWND, UINT, WPARAM, LPARAM); // AboutDialog.cpp 16 + 17 + // Placeholder until Task 10 introduces the calculator window. 18 + static void ToggleCalculator() { /* wired in Task 10 */ } 19 + 20 + static LRESULT CALLBACK OwnerWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 4 21 { 5 - MessageBox(NULL, L"Taskbar Calculator (stub)", L"TaskbarCalculator", MB_OK); 6 - return 0; 22 + if (msg == g_wmTaskbarCreated) { // Explorer restarted 23 + g_tray.Add(hWnd, WM_TRAY_CALLBACK, TRAY_ICON_ID, L"Taskbar Calculator"); 24 + return 0; 25 + } 26 + switch (msg) { 27 + case WM_TRAY_CALLBACK: 28 + if (LOWORD(lParam) == WM_LBUTTONUP) { 29 + ToggleCalculator(); 30 + } else if (LOWORD(lParam) == WM_RBUTTONUP) { 31 + Startup::State s = Startup::Get(); 32 + g_tray.ShowContextMenu(hWnd, s == Startup::State::Enabled, 33 + s != Startup::State::Unavailable); 34 + } 35 + return 0; 36 + case WM_COMMAND: 37 + switch (LOWORD(wParam)) { 38 + case IDM_SHOWHIDE: ToggleCalculator(); return 0; 39 + case IDM_STARTUP: { 40 + Startup::State s = Startup::Get(); 41 + if (s != Startup::State::Unavailable) 42 + Startup::Set(s != Startup::State::Enabled); 43 + return 0; 44 + } 45 + case IDM_ABOUT: 46 + DialogBoxW(GetModuleHandleW(NULL), 47 + MAKEINTRESOURCE(IDD_ABOUT), hWnd, AboutDialogProc); 48 + return 0; 49 + case IDM_EXIT: 50 + DestroyWindow(hWnd); 51 + return 0; 52 + } 53 + return 0; 54 + case WM_DESTROY: 55 + g_tray.Remove(); 56 + PostQuitMessage(0); 57 + return 0; 58 + } 59 + return DefWindowProc(hWnd, msg, wParam, lParam); 60 + } 61 + 62 + int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE, LPWSTR, int) 63 + { 64 + // Single instance: a second launch signals the first and exits. 65 + HANDLE mutex = CreateMutexW(nullptr, TRUE, L"TaskbarCalculator_SingleInstance"); 66 + if (GetLastError() == ERROR_ALREADY_EXISTS) { 67 + HWND existing = FindWindowW(L"TaskbarCalculatorOwner", nullptr); 68 + if (existing) PostMessageW(existing, WM_COMMAND, IDM_SHOWHIDE, 0); 69 + return 0; 70 + } 71 + 72 + winrt::init_apartment(winrt::apartment_type::single_threaded); 73 + 74 + INITCOMMONCONTROLSEX icc{ sizeof(icc), ICC_LINK_CLASS | ICC_STANDARD_CLASSES }; 75 + InitCommonControlsEx(&icc); 76 + 77 + g_wmTaskbarCreated = RegisterWindowMessageW(L"TaskbarCreated"); 78 + 79 + WNDCLASSW wc{}; 80 + wc.lpfnWndProc = OwnerWndProc; 81 + wc.hInstance = hInst; 82 + wc.lpszClassName = L"TaskbarCalculatorOwner"; 83 + RegisterClassW(&wc); 84 + 85 + HWND owner = CreateWindowW(wc.lpszClassName, L"", 0, 0, 0, 0, 0, 86 + HWND_MESSAGE, nullptr, hInst, nullptr); 87 + 88 + g_tray.Add(owner, WM_TRAY_CALLBACK, TRAY_ICON_ID, L"Taskbar Calculator"); 89 + 90 + MSG m; 91 + while (GetMessage(&m, nullptr, 0, 0)) { 92 + TranslateMessage(&m); 93 + DispatchMessage(&m); 94 + } 95 + if (mutex) { ReleaseMutex(mutex); CloseHandle(mutex); } 96 + return (int)m.wParam; 7 97 }
+3
TaskbarCalculator.vcxproj
··· 94 94 </ItemDefinitionGroup> 95 95 <ItemGroup> 96 96 <ClCompile Include="App.cpp" /> 97 + <ClCompile Include="AboutDialog.cpp" /> 98 + <ClCompile Include="TrayIcon.cpp" /> 97 99 <ClCompile Include="Calculator.cpp"> 98 100 <PrecompiledHeader>NotUsing</PrecompiledHeader> 99 101 </ClCompile> ··· 110 112 <ClInclude Include="CalculatorWindow.h" /> 111 113 <ClInclude Include="Settings.h" /> 112 114 <ClInclude Include="StartupManager.h" /> 115 + <ClInclude Include="TrayIcon.h" /> 113 116 <ClInclude Include="resource.h" /> 114 117 <ClInclude Include="stdafx.h" /> 115 118 <ClInclude Include="targetver.h" />
+3
TaskbarCalculator.vcxproj.filters
··· 16 16 </ItemGroup> 17 17 <ItemGroup> 18 18 <ClCompile Include="App.cpp"><Filter>Source Files</Filter></ClCompile> 19 + <ClCompile Include="AboutDialog.cpp"><Filter>Source Files</Filter></ClCompile> 20 + <ClCompile Include="TrayIcon.cpp"><Filter>Source Files</Filter></ClCompile> 19 21 <ClCompile Include="Calculator.cpp"><Filter>Source Files</Filter></ClCompile> 20 22 <ClCompile Include="Settings.cpp"><Filter>Source Files</Filter></ClCompile> 21 23 <ClCompile Include="StartupManager.cpp"><Filter>Source Files</Filter></ClCompile> ··· 27 29 <ClInclude Include="Calculator.h"><Filter>Header Files</Filter></ClInclude> 28 30 <ClInclude Include="Settings.h"><Filter>Header Files</Filter></ClInclude> 29 31 <ClInclude Include="StartupManager.h"><Filter>Header Files</Filter></ClInclude> 32 + <ClInclude Include="TrayIcon.h"><Filter>Header Files</Filter></ClInclude> 30 33 <ClInclude Include="CalculatorWindow.h"><Filter>Header Files</Filter></ClInclude> 31 34 <ClInclude Include="resource.h"><Filter>Header Files</Filter></ClInclude> 32 35 <ClInclude Include="stdafx.h"><Filter>Header Files</Filter></ClInclude>
+42
TrayIcon.cpp
··· 1 + #include "stdafx.h" 2 + #include "TrayIcon.h" 3 + #include "resource.h" 4 + 5 + // Menu command ids (kept in sync with App.cpp). 6 + enum { IDM_SHOWHIDE = 1, IDM_STARTUP = 2, IDM_ABOUT = 3, IDM_EXIT = 4 }; 7 + 8 + bool TrayIcon::Add(HWND owner, UINT cbMsg, UINT iconId, const wchar_t* tip) { 9 + m_nid = {}; 10 + m_nid.cbSize = sizeof(m_nid); 11 + m_nid.hWnd = owner; 12 + m_nid.uID = iconId; 13 + m_nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; 14 + m_nid.uCallbackMessage = cbMsg; 15 + m_nid.hIcon = (HICON)LoadImage(GetModuleHandleW(NULL), 16 + MAKEINTRESOURCE(IDI_ICON1), IMAGE_ICON, 17 + GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0); 18 + lstrcpynW(m_nid.szTip, tip, ARRAYSIZE(m_nid.szTip)); 19 + m_added = Shell_NotifyIconW(NIM_ADD, &m_nid) != FALSE; 20 + return m_added; 21 + } 22 + 23 + void TrayIcon::Remove() { 24 + if (m_added) { Shell_NotifyIconW(NIM_DELETE, &m_nid); m_added = false; } 25 + if (m_nid.hIcon) { DestroyIcon(m_nid.hIcon); m_nid.hIcon = nullptr; } 26 + } 27 + 28 + void TrayIcon::ShowContextMenu(HWND owner, bool startupChecked, bool startupAvailable) { 29 + HMENU menu = CreatePopupMenu(); 30 + AppendMenuW(menu, MF_STRING, IDM_SHOWHIDE, L"Show / Hide"); 31 + AppendMenuW(menu, MF_STRING | (startupChecked ? MF_CHECKED : 0) 32 + | (startupAvailable ? 0 : MF_GRAYED), 33 + IDM_STARTUP, L"Start at login"); 34 + AppendMenuW(menu, MF_SEPARATOR, 0, nullptr); 35 + AppendMenuW(menu, MF_STRING, IDM_ABOUT, L"About"); 36 + AppendMenuW(menu, MF_STRING, IDM_EXIT, L"Exit"); 37 + 38 + POINT pt; GetCursorPos(&pt); 39 + SetForegroundWindow(owner); // so the menu dismisses correctly 40 + TrackPopupMenu(menu, TPM_RIGHTBUTTON, pt.x, pt.y, 0, owner, nullptr); 41 + DestroyMenu(menu); 42 + }
+13
TrayIcon.h
··· 1 + #pragma once 2 + #include <windows.h> 3 + #include <shellapi.h> 4 + 5 + class TrayIcon { 6 + public: 7 + bool Add(HWND owner, UINT cbMsg, UINT iconId, const wchar_t* tip); 8 + void Remove(); 9 + void ShowContextMenu(HWND owner, bool startupChecked, bool startupAvailable); 10 + private: 11 + NOTIFYICONDATAW m_nid{}; 12 + bool m_added = false; 13 + };
+4
stdafx.h
··· 25 25 #include <VsSym32.h> 26 26 #pragma comment(lib, "UxTheme.lib") 27 27 28 + // Common controls (tray, SysLink in About dialog) 29 + #include <CommCtrl.h> 30 + #pragma comment(lib, "comctl32.lib") 31 + 28 32 // ATL definitions and header files 29 33 #define _ATL_APARTMENT_THREADED 30 34 #define _ATL_NO_AUTOMATIC_NAMESPACE