[EXPLORER-NEW]
[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 return pSysTray->NotifyIcon(NIM_ADD, ID_ICON_VOLUME, icon, L"Volume Control");
167 }
168
169 HRESULT STDMETHODCALLTYPE Volume_Update(_In_ CSysTray * pSysTray)
170 {
171 TRACE("Volume_Update\n");
172
173 Volume_IsMute();
174
175 HICON icon;
176 if (g_IsMute)
177 icon = g_hIconMute;
178 else
179 icon = g_hIconVolume;
180
181 return pSysTray->NotifyIcon(NIM_MODIFY, ID_ICON_VOLUME, icon, L"Placeholder");
182 }
183
184 HRESULT STDMETHODCALLTYPE Volume_Shutdown(_In_ CSysTray * pSysTray)
185 {
186 TRACE("Volume_Shutdown\n");
187
188 return pSysTray->NotifyIcon(NIM_DELETE, ID_ICON_VOLUME, NULL, NULL);
189 }
190
191 HRESULT Volume_OnDeviceChange(_In_ CSysTray * pSysTray, WPARAM wParam, LPARAM lParam)
192 {
193 return Volume_FindMixerControl(pSysTray);
194 }
195
196 HRESULT STDMETHODCALLTYPE Volume_Message(_In_ CSysTray * pSysTray, UINT uMsg, WPARAM wParam, LPARAM lParam)
197 {
198 if (uMsg == g_mmDeviceChange)
199 return Volume_OnDeviceChange(pSysTray, wParam, lParam);
200
201 if (uMsg != ID_ICON_VOLUME)
202 {
203 TRACE("Volume_Message received for unknown ID %d, ignoring.\n");
204 return S_FALSE;
205 }
206
207 TRACE("Volume_Message uMsg=%d, w=%x, l=%x\n", uMsg, wParam, lParam);
208
209 Volume_Update(pSysTray);
210
211 switch (lParam)
212 {
213 case WM_LBUTTONDOWN:
214 break;
215 case WM_LBUTTONUP:
216 TRACE("TODO: display volume slider\n");
217 break;
218 case WM_LBUTTONDBLCLK:
219 // FIXME: ensure we are loading the right one
220 ShellExecute(NULL, NULL, L"sndvol32.exe", NULL, NULL, SW_SHOWNORMAL);
221 break;
222 case WM_RBUTTONDOWN:
223 break;
224 case WM_RBUTTONUP:
225 break;
226 case WM_RBUTTONDBLCLK:
227 break;
228 case WM_MOUSEMOVE:
229 break;
230 }
231
232 return S_OK;
233 }