[SNDVOL32] Implement the mute checkbox. The tray dialog is done.
[reactos.git] / base / applications / sndvol32 / tray.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Sound Volume Control
4 * FILE: base/applications/sndvol32/tray.c
5 * PROGRAMMERS: Eric Kohl <eric.kohl@reactos.org>
6 */
7
8 #include "sndvol32.h"
9
10 typedef struct _DIALOG_DATA
11 {
12 HMIXER hMixer;
13 DWORD volumeControlID;
14 DWORD volumeChannels;
15 DWORD volumeMinimum;
16 DWORD volumeMaximum;
17 DWORD volumeStep;
18
19 DWORD maxVolume;
20 DWORD maxChannel;
21 PMIXERCONTROLDETAILS_UNSIGNED volumeInitValues;
22 PMIXERCONTROLDETAILS_UNSIGNED volumeCurrentValues;
23
24 DWORD muteControlID;
25 } DIALOG_DATA, *PDIALOG_DATA;
26
27
28 static VOID
29 OnTrayInitDialog(
30 HWND hwnd,
31 WPARAM wParam,
32 LPARAM lParam)
33 {
34 POINT ptCursor;
35 RECT rcWindow;
36 RECT rcScreen;
37 LONG x, y, cx, cy;
38
39 GetCursorPos(&ptCursor);
40
41 GetWindowRect(hwnd, &rcWindow);
42
43 GetWindowRect(GetDesktopWindow(), &rcScreen);
44
45 cx = rcWindow.right - rcWindow.left;
46 cy = rcWindow.bottom - rcWindow.top;
47
48 if (ptCursor.y + cy > rcScreen.bottom)
49 y = ptCursor.y - cy;
50 else
51 y = ptCursor.y;
52
53 if (ptCursor.x + cx > rcScreen.right)
54 x = ptCursor.x - cx;
55 else
56 x = ptCursor.x;
57
58 SetWindowPos(hwnd, HWND_TOPMOST, x, y, 0, 0, SWP_NOSIZE);
59 }
60
61
62 static
63 VOID
64 OnTrayInitMixer(
65 PDIALOG_DATA pDialogData,
66 HWND hwndDlg)
67 {
68 MIXERLINE mxln;
69 MIXERCONTROL mxc;
70 MIXERLINECONTROLS mxlctrl;
71 MIXERCONTROLDETAILS mxcd;
72 MIXERCONTROLDETAILS_BOOLEAN mxcdBool;
73 DWORD i;
74
75 /* Open the mixer */
76 if (mixerOpen(&pDialogData->hMixer, 0, PtrToUlong(hwndDlg), 0, MIXER_OBJECTF_MIXER | CALLBACK_WINDOW) != MMSYSERR_NOERROR)
77 return;
78
79 /* Retrieve the mixer information */
80 mxln.cbStruct = sizeof(MIXERLINE);
81 mxln.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
82
83 if (mixerGetLineInfo((HMIXEROBJ)pDialogData->hMixer, &mxln, MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_COMPONENTTYPE) != MMSYSERR_NOERROR)
84 return;
85
86 pDialogData->volumeChannels = mxln.cChannels;
87
88 /* Retrieve the line information */
89 mxlctrl.cbStruct = sizeof(MIXERLINECONTROLS);
90 mxlctrl.dwLineID = mxln.dwLineID;
91 mxlctrl.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
92 mxlctrl.cControls = 1;
93 mxlctrl.cbmxctrl = sizeof(MIXERCONTROL);
94 mxlctrl.pamxctrl = &mxc;
95
96 if (mixerGetLineControls((HMIXEROBJ)pDialogData->hMixer, &mxlctrl, MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE) != MMSYSERR_NOERROR)
97 return;
98
99 pDialogData->volumeControlID = mxc.dwControlID;
100 pDialogData->volumeMinimum = mxc.Bounds.dwMinimum;
101 pDialogData->volumeMaximum = mxc.Bounds.dwMaximum;
102 pDialogData->volumeStep = (pDialogData->volumeMaximum - pDialogData->volumeMinimum) / (VOLUME_MAX - VOLUME_MIN);
103
104 /* Allocate a buffer for all channel volume values */
105 pDialogData->volumeInitValues = HeapAlloc(GetProcessHeap(),
106 0,
107 mxln.cChannels * sizeof(MIXERCONTROLDETAILS_UNSIGNED));
108 if (pDialogData->volumeInitValues == NULL)
109 return;
110
111 pDialogData->volumeCurrentValues = HeapAlloc(GetProcessHeap(),
112 0,
113 mxln.cChannels * sizeof(MIXERCONTROLDETAILS_UNSIGNED));
114 if (pDialogData->volumeCurrentValues == NULL)
115 return;
116
117 /* Retrieve the channel volume values */
118 mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
119 mxcd.dwControlID = mxc.dwControlID;
120 mxcd.cChannels = mxln.cChannels;
121 mxcd.cMultipleItems = 0;
122 mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
123 mxcd.paDetails = pDialogData->volumeInitValues;
124
125 if (mixerGetControlDetails((HMIXEROBJ)pDialogData->hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_GETCONTROLDETAILSF_VALUE) != MMSYSERR_NOERROR)
126 return;
127
128 pDialogData->maxVolume = pDialogData->volumeInitValues[0].dwValue;
129 pDialogData->maxChannel = 0;
130 for (i = 1; i < pDialogData->volumeChannels; i++)
131 {
132 if (pDialogData->volumeInitValues[i].dwValue > pDialogData->maxVolume)
133 {
134 pDialogData->maxVolume = pDialogData->volumeInitValues[i].dwValue;
135 pDialogData->maxChannel = i;
136 }
137 }
138
139 /* Initialize the volume trackbar */
140 SendDlgItemMessage(hwndDlg, IDC_LINE_SLIDER_VERT, TBM_SETRANGE, TRUE, MAKELONG(VOLUME_MIN, VOLUME_MAX));
141 SendDlgItemMessage(hwndDlg, IDC_LINE_SLIDER_VERT, TBM_SETPAGESIZE, 0, VOLUME_PAGE_SIZE);
142 SendDlgItemMessage(hwndDlg, IDC_LINE_SLIDER_VERT, TBM_SETPOS, TRUE, VOLUME_MAX -(pDialogData->maxVolume - pDialogData->volumeMinimum) / pDialogData->volumeStep);
143
144 /* Retrieve the mute control information */
145 mxlctrl.cbStruct = sizeof(MIXERLINECONTROLS);
146 mxlctrl.dwLineID = mxln.dwLineID;
147 mxlctrl.dwControlType = MIXERCONTROL_CONTROLTYPE_MUTE;
148 mxlctrl.cControls = 1;
149 mxlctrl.cbmxctrl = sizeof(MIXERCONTROL);
150 mxlctrl.pamxctrl = &mxc;
151
152 if (mixerGetLineControls((HMIXEROBJ)pDialogData->hMixer, &mxlctrl, MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE) != MMSYSERR_NOERROR)
153 return;
154
155 pDialogData->muteControlID = mxc.dwControlID;
156
157 /* Retrieve the mute value */
158 mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
159 mxcd.dwControlID = mxc.dwControlID;
160 mxcd.cChannels = 1;
161 mxcd.cMultipleItems = 0;
162 mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
163 mxcd.paDetails = &mxcdBool;
164
165 if (mixerGetControlDetails((HMIXEROBJ)pDialogData->hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_GETCONTROLDETAILSF_VALUE) != MMSYSERR_NOERROR)
166 return;
167
168 /* Initialize the mute checkbox */
169 SendDlgItemMessage(hwndDlg, IDC_LINE_SWITCH, BM_SETCHECK, (WPARAM)(mxcdBool.fValue ? BST_CHECKED : BST_UNCHECKED), 0);
170 }
171
172
173 static
174 VOID
175 OnCommand(
176 PDIALOG_DATA pDialogData,
177 HWND hwndDlg,
178 WPARAM wParam,
179 LPARAM lParam)
180 {
181 MIXERCONTROLDETAILS mxcd;
182 MIXERCONTROLDETAILS_BOOLEAN mxcdMute;
183
184 if ((LOWORD(wParam) == IDC_LINE_SWITCH) &&
185 (HIWORD(wParam) == BN_CLICKED))
186 {
187 mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
188 mxcd.dwControlID = pDialogData->muteControlID;
189 mxcd.cChannels = 1;
190 mxcd.cMultipleItems = 0;
191 mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
192 mxcd.paDetails = &mxcdMute;
193
194 mxcdMute.fValue = (SendMessage((HWND)lParam, BM_GETCHECK, 0, 0) == BST_CHECKED);
195
196 mixerSetControlDetails((HMIXEROBJ)pDialogData->hMixer,
197 &mxcd,
198 MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE);
199 }
200 }
201
202
203 static
204 VOID
205 OnVScroll(
206 PDIALOG_DATA pDialogData,
207 HWND hwndDlg,
208 WPARAM wParam,
209 LPARAM lParam)
210 {
211 MIXERCONTROLDETAILS mxcd;
212 DWORD dwPos, dwVolume, i;
213
214 switch (LOWORD(wParam))
215 {
216 case TB_THUMBTRACK:
217
218 dwPos = VOLUME_MAX - (DWORD)SendDlgItemMessage(hwndDlg, IDC_LINE_SLIDER_VERT, TBM_GETPOS, 0, 0);
219 dwVolume = (dwPos * pDialogData->volumeStep) + pDialogData->volumeMinimum;
220
221 for (i = 0; i < pDialogData->volumeChannels; i++)
222 {
223 if (i == pDialogData->maxChannel)
224 {
225 pDialogData->volumeCurrentValues[i].dwValue = dwVolume;
226 }
227 else
228 {
229 pDialogData->volumeCurrentValues[i].dwValue =
230 pDialogData->volumeInitValues[i].dwValue * dwVolume / pDialogData-> maxVolume;
231 }
232 }
233
234 mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
235 mxcd.dwControlID = pDialogData->volumeControlID;
236 mxcd.cChannels = pDialogData->volumeChannels;
237 mxcd.cMultipleItems = 0;
238 mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
239 mxcd.paDetails = pDialogData->volumeCurrentValues;
240
241 mixerSetControlDetails((HMIXEROBJ)pDialogData->hMixer,
242 &mxcd,
243 MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE);
244 break;
245
246 case TB_ENDTRACK:
247 PlaySound((LPCTSTR)SND_ALIAS_SYSTEMDEFAULT, NULL, SND_ASYNC | SND_ALIAS_ID);
248 break;
249
250 default:
251 break;
252 }
253 }
254
255
256
257 INT_PTR
258 CALLBACK
259 TrayDlgProc(
260 HWND hwndDlg,
261 UINT uMsg,
262 WPARAM wParam,
263 LPARAM lParam)
264 {
265 PDIALOG_DATA pDialogData;
266
267 pDialogData = (PDIALOG_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
268
269 switch (uMsg)
270 {
271 case WM_INITDIALOG:
272 OnTrayInitDialog(hwndDlg, wParam, lParam);
273
274 pDialogData = (PDIALOG_DATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DIALOG_DATA));
275 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pDialogData);
276
277 if (pDialogData)
278 OnTrayInitMixer(pDialogData, hwndDlg);
279 break;
280
281 case WM_COMMAND:
282 if (pDialogData)
283 OnCommand(pDialogData, hwndDlg, wParam, lParam);
284 break;
285
286 case WM_VSCROLL:
287 if (pDialogData)
288 OnVScroll(pDialogData, hwndDlg, wParam, lParam);
289 break;
290
291 case WM_DESTROY:
292 if (pDialogData)
293 {
294 if (pDialogData->volumeInitValues)
295 HeapFree(GetProcessHeap(), 0, pDialogData->volumeInitValues);
296
297 if (pDialogData->volumeCurrentValues)
298 HeapFree(GetProcessHeap(), 0, pDialogData->volumeCurrentValues);
299
300 if (pDialogData->hMixer)
301 mixerClose(pDialogData->hMixer);
302
303 HeapFree(GetProcessHeap(), 0, pDialogData);
304 pDialogData = NULL;
305 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)NULL);
306 }
307 break;
308
309 case WM_ACTIVATE:
310 if (LOWORD(wParam) == WA_INACTIVE)
311 EndDialog(hwndDlg, IDOK);
312 break;
313 }
314
315 return 0;
316 }
317
318 /* EOF */