d7c041d12e3ba19fffebad2b3e69f66dbb092725
[reactos.git] / dll / shellext / stobject / volume.cpp
1 /*
2 * PROJECT: ReactOS system libraries
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll\win32\stobject\volume.cpp
5 * PURPOSE: Volume notification icon handler
6 * PROGRAMMERS: David Quintana <gigaherz@gmail.com>
7 */
8
9 #include "precomp.h"
10
11 #include <mmsystem.h>
12 #include <mmddk.h>
13
14 WINE_DEFAULT_DEBUG_CHANNEL(stobject);
15
16 HICON g_hIconVolume;
17 HICON g_hIconMute;
18
19 HMIXER g_hMixer;
20 UINT g_mixerId;
21 DWORD g_mixerLineID;
22 DWORD g_muteControlID;
23
24 UINT g_mmDeviceChange;
25
26 BOOL g_IsMute = FALSE;
27
28 static HRESULT __stdcall Volume_FindMixerControl(CSysTray * pSysTray)
29 {
30 MMRESULT result;
31 UINT mixerId = 0;
32 DWORD waveOutId = 0;
33 DWORD param2 = 0;
34
35 TRACE("Volume_FindDefaultMixerID\n");
36
37 result = waveOutMessage((HWAVEOUT) WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET, (DWORD_PTR) &waveOutId, (DWORD_PTR) &param2);
38 if (result)
39 return E_FAIL;
40
41 if (waveOutId == (DWORD)-1)
42 {
43 TRACE("WARNING: waveOut has no default device, trying with first available device...\n", waveOutId);
44
45 mixerId = 0;
46 }
47 else
48 {
49 TRACE("waveOut default device is %d\n", waveOutId);
50
51 result = mixerGetID((HMIXEROBJ) waveOutId, &mixerId, MIXER_OBJECTF_WAVEOUT);
52 if (result)
53 return E_FAIL;
54
55 TRACE("mixerId for waveOut default device is %d\n", mixerId);
56 }
57
58 g_mixerId = mixerId;
59 return S_OK;
60
61 MIXERCAPS mixerCaps;
62 MIXERLINE mixerLine;
63 MIXERCONTROL mixerControl;
64 MIXERLINECONTROLS mixerLineControls;
65
66 g_mixerLineID = -1;
67 g_muteControlID = -1;
68
69 if (mixerGetDevCapsW(g_mixerId, &mixerCaps, sizeof(mixerCaps)))
70 return E_FAIL;
71
72 if (mixerCaps.cDestinations == 0)
73 return S_FALSE;
74
75 TRACE("mixerCaps.cDestinations %d\n", mixerCaps.cDestinations);
76
77 DWORD idx;
78 for (idx = 0; idx < mixerCaps.cDestinations; idx++)
79 {
80 mixerLine.cbStruct = sizeof(mixerLine);
81 mixerLine.dwDestination = idx;
82 if (!mixerGetLineInfoW((HMIXEROBJ) g_mixerId, &mixerLine, 0))
83 {
84 if (mixerLine.dwComponentType >= MIXERLINE_COMPONENTTYPE_DST_SPEAKERS &&
85 mixerLine.dwComponentType <= MIXERLINE_COMPONENTTYPE_DST_HEADPHONES)
86 break;
87 TRACE("Destination %d was not speakers or headphones.\n");
88 }
89 }
90
91 if (idx >= mixerCaps.cDestinations)
92 return E_FAIL;
93
94 TRACE("Valid destination %d found.\n");
95
96 g_mixerLineID = mixerLine.dwLineID;
97
98 mixerLineControls.cbStruct = sizeof(mixerLineControls);
99 mixerLineControls.dwLineID = mixerLine.dwLineID;
100 mixerLineControls.cControls = 1;
101 mixerLineControls.dwControlType = MIXERCONTROL_CONTROLTYPE_MUTE;
102 mixerLineControls.pamxctrl = &mixerControl;
103 mixerLineControls.cbmxctrl = sizeof(mixerControl);
104
105 if (mixerGetLineControlsW((HMIXEROBJ) g_mixerId, &mixerLineControls, MIXER_GETLINECONTROLSF_ONEBYTYPE))
106 return E_FAIL;
107
108 TRACE("Found control id %d for mute: %d\n", mixerControl.dwControlID);
109
110 g_muteControlID = mixerControl.dwControlID;
111
112 return S_OK;
113 }
114
115 HRESULT Volume_IsMute()
116 {
117 #if 0
118 MIXERCONTROLDETAILS mixerControlDetails;
119
120 if (g_mixerId != (UINT)-1 && g_muteControlID != (DWORD)-1)
121 {
122 BOOL detailsResult = 0;
123 mixerControlDetails.cbStruct = sizeof(mixerControlDetails);
124 mixerControlDetails.hwndOwner = 0;
125 mixerControlDetails.dwControlID = g_muteControlID;
126 mixerControlDetails.cChannels = 1;
127 mixerControlDetails.paDetails = &detailsResult;
128 mixerControlDetails.cbDetails = sizeof(detailsResult);
129 if (mixerGetControlDetailsW((HMIXEROBJ) g_mixerId, &mixerControlDetails, 0))
130 return E_FAIL;
131
132 TRACE("Obtained mute status %d\n", detailsResult);
133
134 g_IsMute = detailsResult != 0;
135 }
136 #endif
137 return S_OK;
138 }
139
140 HRESULT STDMETHODCALLTYPE Volume_Init(_In_ CSysTray * pSysTray)
141 {
142 HRESULT hr;
143
144 TRACE("Volume_Init\n");
145
146 if (!g_hMixer)
147 {
148 hr = Volume_FindMixerControl(pSysTray);
149 if (FAILED(hr))
150 return hr;
151
152 g_mmDeviceChange = RegisterWindowMessageW(L"winmm_devicechange");
153 }
154
155 g_hIconVolume = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_VOLUME));
156 g_hIconMute = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_VOLMUTE));
157
158 Volume_IsMute();
159
160 HICON icon;
161 if (g_IsMute)
162 icon = g_hIconMute;
163 else
164 icon = g_hIconVolume;
165
166 pSysTray->NotifyIcon(NIM_ADD, ID_ICON_VOLUME, icon, L"Placeholder");
167 return pSysTray->NotifyIcon(NIM_MODIFY, ID_ICON_VOLUME, icon, L"Placeholder");
168 }
169
170 HRESULT STDMETHODCALLTYPE Volume_Update(_In_ CSysTray * pSysTray)
171 {
172 TRACE("Volume_Update\n");
173
174 Volume_IsMute();
175
176 HICON icon;
177 if (g_IsMute)
178 icon = g_hIconMute;
179 else
180 icon = g_hIconVolume;
181
182 return pSysTray->NotifyIcon(NIM_MODIFY, ID_ICON_VOLUME, icon, L"Placeholder");
183 }
184
185 HRESULT STDMETHODCALLTYPE Volume_Shutdown(_In_ CSysTray * pSysTray)
186 {
187 TRACE("Volume_Shutdown\n");
188
189 return pSysTray->NotifyIcon(NIM_DELETE, ID_ICON_VOLUME, NULL, NULL);
190 }
191
192 HRESULT Volume_OnDeviceChange(_In_ CSysTray * pSysTray, WPARAM wParam, LPARAM lParam)
193 {
194 return Volume_FindMixerControl(pSysTray);
195 }
196
197 HRESULT STDMETHODCALLTYPE Volume_Message(_In_ CSysTray * pSysTray, UINT uMsg, WPARAM wParam, LPARAM lParam)
198 {
199 if (uMsg == g_mmDeviceChange)
200 return Volume_OnDeviceChange(pSysTray, wParam, lParam);
201
202 if (uMsg != ID_ICON_VOLUME)
203 return S_FALSE;
204
205 TRACE("Volume_Message\n");
206
207 TRACE("Calling update...\n");
208 Volume_Update(pSysTray);
209
210 switch (lParam)
211 {
212 case WM_LBUTTONDOWN:
213 break;
214 case WM_LBUTTONUP:
215 TRACE("TODO: display volume slider\n");
216 break;
217 case WM_LBUTTONDBLCLK:
218 // FIXME: ensure we are loading the right one
219 ShellExecute(NULL, NULL, L"sndvol32.exe", NULL, NULL, SW_SHOWNORMAL);
220 break;
221 case WM_RBUTTONDOWN:
222 break;
223 case WM_RBUTTONUP:
224 break;
225 case WM_RBUTTONDBLCLK:
226 break;
227 case WM_MOUSEMOVE:
228 break;
229 }
230
231 return S_OK;
232 }