51f19c2ac519074e4e7db278e28fa4d895326ff3
[reactos.git] / reactos / subsys / system / sndvol32 / sndvol32.c
1 /*
2 * ReactOS Sound Volume Control
3 * Copyright (C) 2004-2005 Thomas Weidenmueller
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * VMware is a registered trademark of VMware, Inc.
20 */
21 /* $Id$
22 *
23 * COPYRIGHT: See COPYING in the top level directory
24 * PROJECT: ReactOS Sound Volume Control
25 * FILE: subsys/system/sndvol32/sndvol32.c
26 * PROGRAMMERS: Thomas Weidenmueller <w3seek@reactos.com>
27 */
28 #include <sndvol32.h>
29
30 HINSTANCE hAppInstance;
31 ATOM MainWindowClass;
32 HWND hMainWnd;
33 HANDLE hAppHeap;
34
35 #define GetDialogData(hwndDlg, type) \
36 ( P##type )GetWindowLongPtr((hwndDlg), DWLP_USER)
37 #define GetWindowData(hwnd, type) \
38 ( P##type )GetWindowLongPtr((hwnd), GWL_USERDATA)
39
40 /******************************************************************************/
41
42 typedef struct _PREFERENCES_CONTEXT
43 {
44 PMIXER_WINDOW MixerWindow;
45 PSND_MIXER Mixer;
46 HWND hwndDlg;
47 } PREFERENCES_CONTEXT, *PPREFERENCES_CONTEXT;
48
49 typedef struct _PREFERENCES_FILL_DEVICES
50 {
51 PPREFERENCES_CONTEXT PrefContext;
52 HWND hComboBox;
53 UINT Selected;
54 } PREFERENCES_FILL_DEVICES, *PPREFERENCES_FILL_DEVICES;
55
56 static BOOL CALLBACK
57 FillDeviceComboBox(PSND_MIXER Mixer,
58 UINT Id,
59 LPCTSTR ProductName,
60 PVOID Context)
61 {
62 LRESULT lres;
63 PPREFERENCES_FILL_DEVICES FillContext = (PPREFERENCES_FILL_DEVICES)Context;
64
65 lres = SendMessage(FillContext->hComboBox,
66 CB_ADDSTRING,
67 0,
68 (LPARAM)ProductName);
69 if (lres != CB_ERR)
70 {
71 /* save the index so we don't screw stuff when the combobox is sorted... */
72 SendMessage(FillContext->hComboBox,
73 CB_SETITEMDATA,
74 (WPARAM)lres,
75 Id);
76
77 if (Id == FillContext->Selected)
78 {
79 SendMessage(FillContext->hComboBox,
80 CB_SETCURSEL,
81 (WPARAM)lres,
82 0);
83 }
84 }
85
86 return TRUE;
87 }
88
89 static INT_PTR CALLBACK
90 DlgPreferencesProc(HWND hwndDlg,
91 UINT uMsg,
92 WPARAM wParam,
93 LPARAM lParam)
94 {
95 PPREFERENCES_CONTEXT Context;
96
97 switch (uMsg)
98 {
99 case WM_COMMAND:
100 {
101 switch (LOWORD(wParam))
102 {
103 case IDOK:
104 case IDCANCEL:
105 {
106 EndDialog(hwndDlg,
107 LOWORD(wParam));
108 break;
109 }
110 }
111 break;
112 }
113
114 case MM_MIXM_LINE_CHANGE:
115 {
116 DPRINT("MM_MIXM_LINE_CHANGE\n");
117 break;
118 }
119
120 case MM_MIXM_CONTROL_CHANGE:
121 {
122 DPRINT("MM_MIXM_CONTROL_CHANGE\n");
123 break;
124 }
125
126 case WM_INITDIALOG:
127 {
128 PREFERENCES_FILL_DEVICES FillDevContext;
129
130 SetWindowLongPtr(hwndDlg,
131 DWLP_USER,
132 (LONG_PTR)lParam);
133 Context = (PPREFERENCES_CONTEXT)((LONG_PTR)lParam);
134 Context->hwndDlg = hwndDlg;
135 Context->Mixer = SndMixerCreate(hwndDlg);
136
137 FillDevContext.PrefContext = Context;
138 FillDevContext.hComboBox = GetDlgItem(hwndDlg,
139 IDC_MIXERDEVICE);
140 FillDevContext.Selected = SndMixerGetSelection(Context->Mixer);
141 SndMixerEnumProducts(Context->Mixer,
142 FillDeviceComboBox,
143 &FillDevContext);
144 return TRUE;
145 }
146
147 case WM_DESTROY:
148 {
149 Context = GetDialogData(hwndDlg,
150 PREFERENCES_CONTEXT);
151 if (Context->Mixer != NULL)
152 {
153 SndMixerDestroy(Context->Mixer);
154 }
155 break;
156 }
157
158 case WM_CLOSE:
159 {
160 EndDialog(hwndDlg,
161 IDCANCEL);
162 break;
163 }
164 }
165
166 return 0;
167 }
168
169 /******************************************************************************/
170
171 static VOID
172 DeleteMixerWindowControls(PMIXER_WINDOW MixerWindow)
173 {
174 }
175
176 BOOL
177 RebuildMixerWindowControls(PMIXER_WINDOW MixerWindow)
178 {
179 DeleteMixerWindowControls(MixerWindow);
180
181 return TRUE;
182 }
183
184 LRESULT CALLBACK
185 MainWindowProc(HWND hwnd,
186 UINT uMsg,
187 WPARAM wParam,
188 LPARAM lParam)
189 {
190 PMIXER_WINDOW MixerWindow;
191 LRESULT Result = 0;
192
193 switch (uMsg)
194 {
195 case WM_COMMAND:
196 {
197 MixerWindow = GetWindowData(hwnd,
198 MIXER_WINDOW);
199
200 switch (LOWORD(wParam))
201 {
202 case IDC_PROPERTIES:
203 {
204 PREFERENCES_CONTEXT Preferences;
205
206 Preferences.MixerWindow = MixerWindow;
207 Preferences.Mixer = NULL;
208
209 if (DialogBoxParam(hAppInstance,
210 MAKEINTRESOURCE(IDD_PREFERENCES),
211 hwnd,
212 DlgPreferencesProc,
213 (LPARAM)&Preferences) == IDOK)
214 {
215 /* FIXME - update window */
216 }
217 break;
218 }
219
220 case IDC_EXIT:
221 {
222 PostQuitMessage(0);
223 break;
224 }
225 }
226 break;
227 }
228
229 case MM_MIXM_LINE_CHANGE:
230 {
231 DPRINT("MM_MIXM_LINE_CHANGE\n");
232 break;
233 }
234
235 case MM_MIXM_CONTROL_CHANGE:
236 {
237 DPRINT("MM_MIXM_CONTROL_CHANGE\n");
238 break;
239 }
240
241 case WM_CREATE:
242 {
243 MixerWindow = ((LPCREATESTRUCT)lParam)->lpCreateParams;
244 SetWindowLongPtr(hwnd,
245 GWL_USERDATA,
246 (LONG_PTR)MixerWindow);
247 MixerWindow->hWnd = hwnd;
248 MixerWindow->hStatusBar = CreateStatusWindow(WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS,
249 NULL,
250 hwnd,
251 0);
252 if (MixerWindow->hStatusBar != NULL)
253 {
254 MixerWindow->Mixer = SndMixerCreate(MixerWindow->hWnd);
255 if (MixerWindow->Mixer != NULL)
256 {
257 TCHAR szProduct[MAXPNAMELEN];
258
259 if (SndMixerGetProductName(MixerWindow->Mixer,
260 szProduct,
261 sizeof(szProduct) / sizeof(szProduct[0])) > 0)
262 {
263 SendMessage(MixerWindow->hStatusBar,
264 WM_SETTEXT,
265 0,
266 (LPARAM)szProduct);
267 }
268
269 if (!RebuildMixerWindowControls(MixerWindow))
270 {
271 DPRINT("Rebuilding mixer window controls failed!\n");
272 SndMixerDestroy(MixerWindow->Mixer);
273 Result = -1;
274 }
275 }
276 else
277 {
278 Result = -1;
279 }
280 }
281 else
282 {
283 DPRINT("Failed to create status window!\n");
284 Result = -1;
285 }
286 break;
287 }
288
289 case WM_DESTROY:
290 {
291 MixerWindow = GetWindowData(hwnd,
292 MIXER_WINDOW);
293 if (MixerWindow->Mixer != NULL)
294 {
295 SndMixerDestroy(MixerWindow->Mixer);
296 }
297 break;
298 }
299
300 case WM_CLOSE:
301 {
302 PostQuitMessage(0);
303 break;
304 }
305
306 default:
307 {
308 Result = DefWindowProc(hwnd,
309 uMsg,
310 wParam,
311 lParam);
312 break;
313 }
314 }
315
316 return Result;
317 }
318
319 static BOOL
320 RegisterApplicationClasses(VOID)
321 {
322 WNDCLASSEX wc;
323
324 wc.cbSize = sizeof(WNDCLASSEX);
325 wc.style = CS_HREDRAW | CS_VREDRAW;
326 wc.lpfnWndProc = MainWindowProc;
327 wc.cbClsExtra = 0;
328 wc.cbWndExtra = sizeof(PMIXER_WINDOW);
329 wc.hInstance = hAppInstance;
330 wc.hIcon = LoadIcon(hAppInstance,
331 MAKEINTRESOURCE(IDI_MAINAPP));
332 wc.hCursor = LoadCursor(NULL,
333 IDC_ARROW);
334 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
335 wc.lpszMenuName = NULL;
336 wc.lpszClassName = SZ_APP_CLASS;
337 wc.hIconSm = NULL;
338 MainWindowClass = RegisterClassEx(&wc);
339
340 return MainWindowClass != 0;
341 }
342
343 static VOID
344 UnregisterApplicationClasses(VOID)
345 {
346 UnregisterClass(SZ_APP_CLASS,
347 hAppInstance);
348 }
349
350 static HWND
351 CreateApplicationWindow(VOID)
352 {
353 LPTSTR lpAppTitle;
354 HWND hWnd;
355
356 PMIXER_WINDOW MixerWindow = HeapAlloc(hAppHeap,
357 0,
358 sizeof(MIXER_WINDOW));
359 if (MixerWindow == NULL)
360 {
361 return NULL;
362 }
363
364 /* load the application title */
365 if (AllocAndLoadString(&lpAppTitle,
366 hAppInstance,
367 IDS_SNDVOL32) == 0)
368 {
369 lpAppTitle = NULL;
370 }
371
372 if (mixerGetNumDevs() > 0)
373 {
374 hWnd = CreateWindowEx(WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT,
375 SZ_APP_CLASS,
376 lpAppTitle,
377 WS_DLGFRAME | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE,
378 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
379 NULL,
380 LoadMenu(hAppInstance,
381 MAKEINTRESOURCE(IDM_MAINMENU)),
382 hAppInstance,
383 MixerWindow);
384 }
385 else
386 {
387 LPTSTR lpErrMessage;
388
389 /*
390 * no mixer devices are available!
391 */
392
393 hWnd = NULL;
394 AllocAndLoadString(&lpErrMessage,
395 hAppInstance,
396 IDS_NOMIXERDEVICES);
397 MessageBox(NULL,
398 lpErrMessage,
399 lpAppTitle,
400 MB_ICONINFORMATION);
401 LocalFree(lpErrMessage);
402 }
403
404 if (lpAppTitle != NULL)
405 {
406 LocalFree(lpAppTitle);
407 }
408
409 if (hWnd == NULL)
410 {
411 HeapFree(hAppHeap,
412 0,
413 MixerWindow);
414 }
415
416 return hWnd;
417 }
418
419 int WINAPI
420 WinMain(HINSTANCE hInstance,
421 HINSTANCE hPrevInstance,
422 LPSTR lpszCmdLine,
423 int nCmdShow)
424 {
425 MSG Msg;
426
427 hAppInstance = hInstance;
428 hAppHeap = GetProcessHeap();
429
430 InitCommonControls();
431
432 if (!RegisterApplicationClasses())
433 {
434 DPRINT("Failed to register application classes (LastError: %d)!\n", GetLastError());
435 return 1;
436 }
437
438 hMainWnd = CreateApplicationWindow();
439 if (hMainWnd == NULL)
440 {
441 DPRINT("Failed to creat application window (LastError: %d)!\n", GetLastError());
442 return 1;
443 }
444
445 while (GetMessage(&Msg,
446 NULL,
447 0,
448 0))
449 {
450 TranslateMessage(&Msg);
451 DispatchMessage(&Msg);
452 }
453
454 DestroyWindow(hMainWnd);
455
456 UnregisterApplicationClasses();
457
458 return 0;
459 }
460