1 /*
2  * PROJECT:     ReactOS Task Manager
3  * LICENSE:     LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4  * PURPOSE:     Tray Icon.
5  * COPYRIGHT:   Copyright 1999-2001 Brian Palmer <brianp@reactos.org>
6  *              Copyright 2005 Klemens Friedl <frik85@reactos.at>
7  */
8 
9 #include "precomp.h"
10 
11 static HICON
TrayIcon_GetProcessorUsageIcon(_In_ ULONG CpuUsage)12 TrayIcon_GetProcessorUsageIcon(
13     _In_ ULONG CpuUsage)
14 {
15     HICON    hTrayIcon = NULL;
16     HDC      hScreenDC = NULL;
17     HDC      hDC = NULL;
18     HBITMAP  hBitmap = NULL;
19     HBITMAP  hOldBitmap = NULL;
20     HBITMAP  hBitmapMask = NULL;
21     ICONINFO iconInfo;
22     int      nLinesToDraw;
23     HBRUSH   hBitmapBrush = NULL;
24     RECT     rc;
25 
26     /* Get a handle to the screen DC */
27     hScreenDC = GetDC(NULL);
28     if (!hScreenDC)
29         goto done;
30 
31     /* Create our own DC from it */
32     hDC = CreateCompatibleDC(hScreenDC);
33     if (!hDC)
34         goto done;
35 
36     /*
37      * Load the bitmaps
38      */
39     hBitmap = LoadBitmapW(hInst, MAKEINTRESOURCEW(IDB_TRAYICON));
40     hBitmapMask = LoadBitmapW(hInst, MAKEINTRESOURCEW(IDB_TRAYMASK));
41     if (!hBitmap || !hBitmapMask)
42         goto done;
43 
44     hBitmapBrush = CreateSolidBrush(RGB(0, 255, 0));
45     if (!hBitmapBrush)
46         goto done;
47 
48     /*
49      * Select the bitmap into our device context
50      * so we can draw on it.
51      */
52     hOldBitmap = SelectObject(hDC, hBitmap);
53 
54     /*
55      * Calculate how many lines to draw
56      * since we have 11 rows of space
57      * to draw the cpu usage instead of
58      * just having 10.
59      */
60     nLinesToDraw = (CpuUsage + (CpuUsage / 10)) / 11;
61     rc.left = 3;
62     rc.top = 12 - nLinesToDraw;
63     rc.right = 13;
64     rc.bottom = 13;
65 
66     /* Now draw the cpu usage */
67     if (nLinesToDraw)
68         FillRect(hDC, &rc, hBitmapBrush);
69 
70     /*
71      * Now that we are done drawing put the
72      * old bitmap back.
73      */
74     hBitmap = SelectObject(hDC, hOldBitmap);
75     hOldBitmap = NULL;
76 
77     iconInfo.fIcon = TRUE;
78     iconInfo.hbmMask = hBitmapMask;
79     iconInfo.hbmColor = hBitmap;
80 
81     hTrayIcon = CreateIconIndirect(&iconInfo);
82 
83 done:
84     /*
85      * Cleanup
86      */
87     if (hScreenDC)
88         ReleaseDC(NULL, hScreenDC);
89     if (hDC)
90         DeleteDC(hDC);
91     if (hBitmapBrush)
92         DeleteObject(hBitmapBrush);
93     if (hBitmap)
94         DeleteObject(hBitmap);
95     if (hBitmapMask)
96         DeleteObject(hBitmapMask);
97 
98     /* Return the newly created tray icon (if successful) */
99     return hTrayIcon;
100 }
101 
102 static BOOL
TrayIcon_Update(_In_ DWORD dwMessage)103 TrayIcon_Update(
104     _In_ DWORD dwMessage)
105 {
106     static WCHAR szMsg[64] = L"";
107 
108     NOTIFYICONDATAW nid;
109     ULONG CpuUsage;
110     HICON hIcon = NULL;
111     BOOL  bRetVal;
112 
113     if (!*szMsg)
114         LoadStringW(hInst, IDS_MSG_TRAYICONCPUUSAGE, szMsg, _countof(szMsg));
115 
116     ZeroMemory(&nid, sizeof(nid));
117 
118     CpuUsage = PerfDataGetProcessorUsage();
119     hIcon = TrayIcon_GetProcessorUsageIcon(CpuUsage);
120 
121     nid.cbSize = sizeof(nid);
122     nid.hWnd = hMainWnd;
123     nid.uID = 0;
124     nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
125     nid.uCallbackMessage = WM_ONTRAYICON;
126     nid.hIcon = hIcon;
127 
128     StringCchPrintfW(nid.szTip, _countof(nid.szTip), szMsg, CpuUsage);
129 
130     bRetVal = Shell_NotifyIconW(dwMessage, &nid);
131 
132     if (hIcon)
133         DestroyIcon(hIcon);
134 
135     return bRetVal;
136 }
137 
TrayIcon_AddIcon(VOID)138 BOOL TrayIcon_AddIcon(VOID)
139 {
140     return TrayIcon_Update(NIM_ADD);
141 }
142 
TrayIcon_RemoveIcon(VOID)143 BOOL TrayIcon_RemoveIcon(VOID)
144 {
145     NOTIFYICONDATAW nid;
146 
147     ZeroMemory(&nid, sizeof(nid));
148 
149     nid.cbSize = sizeof(nid);
150     nid.hWnd = hMainWnd;
151     nid.uID = 0;
152     nid.uFlags = 0;
153     nid.uCallbackMessage = WM_ONTRAYICON;
154 
155     return Shell_NotifyIconW(NIM_DELETE, &nid);
156 }
157 
TrayIcon_UpdateIcon(VOID)158 BOOL TrayIcon_UpdateIcon(VOID)
159 {
160     return TrayIcon_Update(NIM_MODIFY);
161 }
162