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: standalone always-on-top calculator window, reusing input/formatting

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

Marco Maroni (Jul 14, 2026, 3:21 PM +0200) 1fa8e05f 6675d8c4

+63 -82
+8 -2
App.cpp
··· 3 3 #include <winrt/Windows.Foundation.h> 4 4 #include "TrayIcon.h" 5 5 #include "StartupManager.h" 6 + #include "CalculatorWindow.h" 6 7 #include "resource.h" 7 8 8 9 enum { IDM_SHOWHIDE = 1, IDM_STARTUP = 2, IDM_ABOUT = 3, IDM_EXIT = 4 }; ··· 11 12 12 13 UINT g_wmTaskbarCreated = 0; 13 14 static TrayIcon g_tray; 15 + static CCalculatorWindow* g_calc = nullptr; 14 16 15 17 INT_PTR CALLBACK AboutDialogProc(HWND, UINT, WPARAM, LPARAM); // AboutDialog.cpp 16 18 17 - // Placeholder until Task 10 introduces the calculator window. 18 - static void ToggleCalculator() { /* wired in Task 10 */ } 19 + static void ToggleCalculator() { if (g_calc) g_calc->ToggleVisible(); } 19 20 20 21 static LRESULT CALLBACK OwnerWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 21 22 { ··· 87 88 88 89 g_tray.Add(owner, WM_TRAY_CALLBACK, TRAY_ICON_ID, L"Taskbar Calculator"); 89 90 91 + g_calc = new CCalculatorWindow(); 92 + g_calc->CreateStandalone(); 93 + 90 94 MSG m; 91 95 while (GetMessage(&m, nullptr, 0, 0)) { 92 96 TranslateMessage(&m); 93 97 DispatchMessage(&m); 94 98 } 99 + delete g_calc; 100 + g_calc = nullptr; 95 101 if (mutex) { ReleaseMutex(mutex); CloseHandle(mutex); } 96 102 return (int)m.wParam; 97 103 }
+45 -74
CalculatorWindow.cpp
··· 105 105 //////////////////////////////////////////////////////////////////////////////// 106 106 // CCalculatorWindow 107 107 CCalculatorWindow::CCalculatorWindow() : 108 - m_pDeskBand(NULL), 109 108 m_fHasFocus(FALSE), 110 109 m_ptrVisualStyle(CVisualStyle::Create()), 111 110 m_calc() ··· 127 126 //////////////////////////////////////////////////////////////////////////////// 128 127 // 129 128 130 - BOOL CCalculatorWindow::Create( 131 - HWND hwndParent, 132 - LPUNKNOWN pDeskBand, 133 - LPUNKNOWN pInputObjectSite) 129 + BOOL CCalculatorWindow::CreateStandalone() 134 130 { 135 - if(!__super::Create(hwndParent)) 136 - return FALSE; 137 - 138 - ATLASSERT(pDeskBand); 139 - m_pDeskBand = pDeskBand; 131 + RECT rc = { 0, 0, 220, 48 }; 132 + // Top-level popup, always-on-top, tool window (no taskbar/Alt-Tab button). 133 + HWND hwnd = __super::Create(NULL, rc, L"Taskbar Calculator", 134 + WS_POPUP | WS_CAPTION | WS_SYSMENU, 135 + WS_EX_TOPMOST | WS_EX_TOOLWINDOW); 136 + if (!hwnd) return FALSE; 140 137 141 - ATLASSERT(pInputObjectSite); 142 - m_spInputObjectSite = pInputObjectSite; 138 + m_hwndEdit = CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("EDIT"), TEXT("0"), 139 + WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | ES_RIGHT | ES_NUMBER, 140 + 0, 0, 0, 0, m_hWnd, NULL, _AtlBaseModule.GetModuleInstance(), 0); 143 141 144 - m_hwndEdit = CreateWindowEx( 145 - WS_EX_CLIENTEDGE, 146 - TEXT("EDIT"), 147 - TEXT("0"), 148 - WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | ES_RIGHT | ES_NUMBER, 149 - 0, 150 - 0, 151 - 0, 152 - 0, 153 - m_hWnd, 154 - NULL, 155 - _AtlBaseModule.GetModuleInstance(), 156 - 0); 142 + SetWindowFont(m_hwndEdit, m_ptrVisualStyle->GetFont(), TRUE); 143 + wpOrigEditProc = (WNDPROC)::SetWindowLongPtr(m_hwndEdit, GWLP_WNDPROC, (LONG_PTR)WndEditProc); 144 + if (wpOrigEditProc == 0) return FALSE; 145 + ::SetWindowLongPtr(m_hwndEdit, GWLP_USERDATA, (LONG_PTR)this); 157 146 158 - SetWindowFont(m_hwndEdit, m_ptrVisualStyle->GetFont(), TRUE); 159 - 160 - wpOrigEditProc = (WNDPROC)::SetWindowLongPtr(m_hwndEdit, GWLP_WNDPROC, (LONG_PTR)WndEditProc); 161 - if (wpOrigEditProc == 0) 162 - return FALSE; 147 + POINTL ideal = CalcIdealSize(); 148 + SetWindowPos(NULL, 0, 0, ideal.x + 24, ideal.y + 16, SWP_NOMOVE | SWP_NOZORDER); 149 + return TRUE; 150 + } 163 151 164 - ::SetWindowLongPtr(m_hwndEdit, GWLP_USERDATA, (LONG_PTR)this); 165 - 166 - 167 - return TRUE; 152 + void CCalculatorWindow::ToggleVisible() 153 + { 154 + if (m_shown) { 155 + ShowWindow(SW_HIDE); 156 + m_shown = false; 157 + } else { 158 + SetWindowPos(HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); 159 + SetForegroundWindow(m_hWnd); 160 + ::SetFocus(m_hwndEdit); 161 + m_shown = true; 162 + } 168 163 } 169 164 170 165 POINTL CCalculatorWindow::CalcMinimalSize() const ··· 218 213 BOOL& /*bHandled*/) 219 214 { 220 215 m_fHasFocus = (uMsg == WM_SETFOCUS); 221 - 222 - if(m_spInputObjectSite) 223 - m_spInputObjectSite->OnFocusChangeIS(m_pDeskBand, m_fHasFocus); 224 216 225 217 if ( m_fHasFocus ) 226 218 ReadRegionalSettings(); ··· 319 311 return 0; 320 312 } 321 313 314 + LRESULT CCalculatorWindow::OnClose(UINT, WPARAM, LPARAM, BOOL&) 315 + { 316 + // Hide to tray instead of destroying. 317 + ShowWindow(SW_HIDE); 318 + m_shown = false; 319 + return 0; 320 + } 321 + 322 + LRESULT CCalculatorWindow::OnLButtonDown(UINT, WPARAM, LPARAM, BOOL&) 323 + { 324 + // Allow dragging the window by its body. 325 + ReleaseCapture(); 326 + SendMessage(WM_NCLBUTTONDOWN, HTCAPTION, 0); 327 + return 0; 328 + } 329 + 322 330 void CCalculatorWindow::Paint(HDC hdc, const RECT& rcPaint) const 323 331 { 324 332 m_ptrVisualStyle->DrawBackground(m_hWnd, hdc, rcPaint); ··· 444 452 case CALC_000: 445 453 case CALC_NEG: 446 454 case CALC_PERC: 447 - case CALC_EURO: 448 - case CALC_L: 449 - case CALC_X: 450 455 case CALC_I: 451 - case CALC_A: 452 - case CALC_B: 453 - case CALC_C: 454 - case CALC_D: 455 - case CALC_E: 456 - case CALC_F: 457 456 c = (TCHAR)wParam; 458 457 break; 459 458 case 'z': ··· 471 470 case 'p': 472 471 c = CALC_NEG; 473 472 break; 474 - case 'r': 475 - c = CALC_EURO; 476 - break; 477 - case 'l': 478 - c = CALC_L; 479 - break; 480 - case 'x': 481 - c = CALC_X; 482 - break; 483 - case 'a': 484 - c = CALC_A; 485 - break; 486 - case 'b': 487 - c = CALC_B; 488 - break; 489 - case 'c': 490 - c = CALC_C; 491 - break; 492 - case 'd': 493 - c = CALC_D; 494 - break; 495 - case 'e': 496 - c = CALC_E; 497 - break; 498 - case 'f': 499 - c = CALC_F; 500 - break; 501 473 default: 502 474 bChangeState = false; 503 475 } ··· 540 512 { 541 513 _tcscpy_s(strOutput, 1024, strInput); 542 514 543 - if (m_calc.get_current_base() == calc::decimal) 544 515 { 545 516 LPTSTR cDecSep = _tcschr(strOutput, CALC_P); 546 517 if (cDecSep != NULL)
+8 -6
CalculatorWindow.h
··· 13 13 CCalculatorWindow(); 14 14 ~CCalculatorWindow(); 15 15 16 - BOOL Create( 17 - HWND hwndParent, 18 - LPUNKNOWN pDeskBand, 19 - LPUNKNOWN pInputObjectSite); 16 + BOOL CreateStandalone(); 17 + void ToggleVisible(); 18 + bool IsShown() const { return m_shown; } 20 19 21 20 POINTL CalcMinimalSize() const; 22 21 POINTL CalcIdealSize() const; ··· 39 38 MESSAGE_HANDLER(WM_KILLFOCUS, OnFocus) 40 39 MESSAGE_HANDLER(WM_POWERBROADCAST, OnPowerBroadcast) 41 40 MESSAGE_HANDLER(WM_THEMECHANGED, OnThemeChanged) 41 + MESSAGE_HANDLER(WM_CLOSE, OnClose) 42 + MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown) 42 43 END_MSG_MAP() 43 44 44 45 // Handler prototypes: ··· 53 54 LRESULT OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); 54 55 LRESULT OnPowerBroadcast(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); 55 56 LRESULT OnThemeChanged(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); 57 + LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); 58 + LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); 56 59 57 60 void Paint(HDC hdc, const RECT& rcPaint) const; 58 61 // UINT_PTR SetUpdateTimer(); ··· 68 71 69 72 70 73 private: 71 - IUnknown* m_pDeskBand; 72 74 BOOL m_fHasFocus; 73 - CComQIPtr<IInputObjectSite> m_spInputObjectSite; 75 + bool m_shown = false; 74 76 CAutoPtr<CVisualStyle> m_ptrVisualStyle; 75 77 76 78 //const DateFormat* m_pDateFormat;
+1
TaskbarCalculator.vcxproj
··· 99 99 <ClCompile Include="Calculator.cpp"> 100 100 <PrecompiledHeader>NotUsing</PrecompiledHeader> 101 101 </ClCompile> 102 + <ClCompile Include="CalculatorWindow.cpp" /> 102 103 <ClCompile Include="Settings.cpp" /> 103 104 <ClCompile Include="StartupManager.cpp" /> 104 105 <ClCompile Include="Utils.cpp" />
+1
TaskbarCalculator.vcxproj.filters
··· 19 19 <ClCompile Include="AboutDialog.cpp"><Filter>Source Files</Filter></ClCompile> 20 20 <ClCompile Include="TrayIcon.cpp"><Filter>Source Files</Filter></ClCompile> 21 21 <ClCompile Include="Calculator.cpp"><Filter>Source Files</Filter></ClCompile> 22 + <ClCompile Include="CalculatorWindow.cpp"><Filter>Source Files</Filter></ClCompile> 22 23 <ClCompile Include="Settings.cpp"><Filter>Source Files</Filter></ClCompile> 23 24 <ClCompile Include="StartupManager.cpp"><Filter>Source Files</Filter></ClCompile> 24 25 <ClCompile Include="Utils.cpp"><Filter>Source Files</Filter></ClCompile>