9feb6c5a06aa1229886c81ea9b0b89b77140b8e5
[reactos.git] / reactos / subsys / system / sndvol32 / sndvol32.c
1 /*
2 * ReactOS Sound Volume Control
3 * Copyright (C) 2004 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, UINT Id, LPCTSTR ProductName, PVOID Context)
58 {
59 LRESULT lres;
60 PPREFERENCES_FILL_DEVICES FillContext = (PPREFERENCES_FILL_DEVICES)Context;
61
62 lres = SendMessage(FillContext->hComboBox, CB_ADDSTRING, 0, (LPARAM)ProductName);
63 if(lres != CB_ERR)
64 {
65 /* save the index so we don't screw stuff when the combobox is sorted... */
66 SendMessage(FillContext->hComboBox, CB_SETITEMDATA, (WPARAM)lres, Id);
67
68 if(Id == FillContext->Selected)
69 {
70 SendMessage(FillContext->hComboBox, CB_SETCURSEL, (WPARAM)lres, 0);
71 }
72 }
73
74 return TRUE;
75 }
76
77 static INT_PTR CALLBACK
78 DlgPreferencesProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
79 {
80 PPREFERENCES_CONTEXT Context;
81
82 switch(uMsg)
83 {
84 case WM_COMMAND:
85 {
86 switch(LOWORD(wParam))
87 {
88 case IDOK:
89 case IDCANCEL:
90 {
91 EndDialog(hwndDlg, LOWORD(wParam));
92 break;
93 }
94 }
95 break;
96 }
97
98 case MM_MIXM_LINE_CHANGE:
99 {
100 DBG("MM_MIXM_LINE_CHANGE\n");
101 break;
102 }
103
104 case MM_MIXM_CONTROL_CHANGE:
105 {
106 DBG("MM_MIXM_CONTROL_CHANGE\n");
107 break;
108 }
109
110 case WM_INITDIALOG:
111 {
112 PREFERENCES_FILL_DEVICES FillDevContext;
113
114 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)lParam);
115 Context = (PPREFERENCES_CONTEXT)((LONG_PTR)lParam);
116 Context->hwndDlg = hwndDlg;
117 Context->Mixer = SndMixerCreate(hwndDlg);
118
119 FillDevContext.PrefContext = Context;
120 FillDevContext.hComboBox = GetDlgItem(hwndDlg, IDC_MIXERDEVICE);
121 FillDevContext.Selected = SndMixerGetSelection(Context->Mixer);
122 SndMixerEnumProducts(Context->Mixer,
123 FillDeviceComboBox,
124 &FillDevContext);
125 return TRUE;
126 }
127
128 case WM_DESTROY:
129 {
130 Context = GetDialogData(hwndDlg, PREFERENCES_CONTEXT);
131 if(Context->Mixer != NULL)
132 {
133 SndMixerDestroy(Context->Mixer);
134 }
135 break;
136 }
137
138 case WM_CLOSE:
139 {
140 EndDialog(hwndDlg, IDCANCEL);
141 break;
142 }
143 }
144
145 return 0;
146 }
147
148 /******************************************************************************/
149
150 static VOID
151 DeleteMixerWindowControls(PMIXER_WINDOW MixerWindow)
152 {
153 }
154
155 BOOL
156 RebuildMixerWindowControls(PMIXER_WINDOW MixerWindow)
157 {
158 DeleteMixerWindowControls(MixerWindow);
159
160 return TRUE;
161 }
162
163 LRESULT CALLBACK
164 MainWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
165 {
166 PMIXER_WINDOW MixerWindow;
167 LRESULT Result = 0;
168
169 switch(uMsg)
170 {
171 case WM_COMMAND:
172 {
173 MixerWindow = GetWindowData(hwnd, MIXER_WINDOW);
174
175 switch(LOWORD(wParam))
176 {
177 case IDC_PROPERTIES:
178 {
179 PREFERENCES_CONTEXT Preferences;
180
181 Preferences.MixerWindow = MixerWindow;
182 Preferences.Mixer = NULL;
183
184 if(DialogBoxParam(hAppInstance,
185 MAKEINTRESOURCE(IDD_PREFERENCES),
186 hwnd,
187 DlgPreferencesProc,
188 (LPARAM)&Preferences) == IDOK)
189 {
190 /* FIXME - update window */
191 }
192 break;
193 }
194
195 case IDC_EXIT:
196 {
197 PostQuitMessage(0);
198 break;
199 }
200 }
201 break;
202 }
203
204 case MM_MIXM_LINE_CHANGE:
205 {
206 DBG("MM_MIXM_LINE_CHANGE\n");
207 break;
208 }
209
210 case MM_MIXM_CONTROL_CHANGE:
211 {
212 DBG("MM_MIXM_CONTROL_CHANGE\n");
213 break;
214 }
215
216 case WM_CREATE:
217 {
218 MixerWindow = ((LPCREATESTRUCT)lParam)->lpCreateParams;
219 SetWindowLongPtr(hwnd, GWL_USERDATA, (LONG_PTR)MixerWindow);
220 MixerWindow->hWnd = hwnd;
221 MixerWindow->hStatusBar = CreateStatusWindow(WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS,
222 NULL, hwnd, 0);
223 if(MixerWindow->hStatusBar != NULL)
224 {
225 MixerWindow->Mixer = SndMixerCreate(MixerWindow->hWnd);
226 if(MixerWindow->Mixer != NULL)
227 {
228 TCHAR szProduct[MAXPNAMELEN];
229
230 if(SndMixerGetProductName(MixerWindow->Mixer, szProduct, sizeof(szProduct) / sizeof(szProduct[0])) > 0)
231 {
232 SendMessage(MixerWindow->hStatusBar, WM_SETTEXT, 0, (LPARAM)szProduct);
233 }
234
235 if(!RebuildMixerWindowControls(MixerWindow))
236 {
237 DBG("Rebuilding mixer window controls failed!\n");
238 SndMixerDestroy(MixerWindow->Mixer);
239 Result = -1;
240 }
241 }
242 else
243 {
244 Result = -1;
245 }
246 }
247 else
248 {
249 DBG("Failed to create status window!\n");
250 Result = -1;
251 }
252 break;
253 }
254
255 case WM_DESTROY:
256 {
257 MixerWindow = GetWindowData(hwnd, MIXER_WINDOW);
258 if(MixerWindow->Mixer != NULL)
259 {
260 SndMixerDestroy(MixerWindow->Mixer);
261 }
262 break;
263 }
264
265 case WM_CLOSE:
266 {
267 PostQuitMessage(0);
268 break;
269 }
270
271 default:
272 {
273 Result = DefWindowProc(hwnd, uMsg, wParam, lParam);
274 }
275 }
276
277 return Result;
278 }
279
280 static BOOL
281 RegisterApplicationClasses(VOID)
282 {
283 WNDCLASSEX wc;
284
285 wc.cbSize = sizeof(WNDCLASSEX);
286 wc.style = CS_HREDRAW | CS_VREDRAW;
287 wc.lpfnWndProc = MainWindowProc;
288 wc.cbClsExtra = 0;
289 wc.cbWndExtra = sizeof(PMIXER_WINDOW);
290 wc.hInstance = hAppInstance;
291 wc.hIcon = LoadIcon(hAppInstance, MAKEINTRESOURCE(IDI_MAINAPP));
292 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
293 wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
294 wc.lpszMenuName = NULL;
295 wc.lpszClassName = SZ_APP_CLASS;
296 wc.hIconSm = NULL;
297 MainWindowClass = RegisterClassEx(&wc);
298
299 return MainWindowClass != 0;
300 }
301
302 static VOID
303 UnregisterApplicationClasses(VOID)
304 {
305 UnregisterClass(SZ_APP_CLASS, hAppInstance);
306 }
307
308 static HWND
309 CreateApplicationWindow(VOID)
310 {
311 LPTSTR lpAppTitle;
312 HWND hWnd;
313
314 PMIXER_WINDOW MixerWindow = HeapAlloc(hAppHeap, 0, sizeof(MIXER_WINDOW));
315 if(MixerWindow == NULL)
316 {
317 return NULL;
318 }
319
320 /* load the application title */
321 if(RosAllocAndLoadString(&lpAppTitle,
322 hAppInstance,
323 IDS_SNDVOL32) == 0)
324 {
325 lpAppTitle = NULL;
326 }
327
328 if(mixerGetNumDevs() > 0)
329 {
330 hWnd = CreateWindowEx(WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT,
331 SZ_APP_CLASS,
332 lpAppTitle,
333 WS_DLGFRAME | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE,
334 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
335 NULL,
336 LoadMenu(hAppInstance, MAKEINTRESOURCE(IDM_MAINMENU)),
337 hAppInstance,
338 MixerWindow);
339 }
340 else
341 {
342 LPTSTR lpErrMessage;
343
344 /*
345 * no mixer devices are available!
346 */
347
348 hWnd = NULL;
349 RosAllocAndLoadString(&lpErrMessage,
350 hAppInstance,
351 IDS_NOMIXERDEVICES);
352 MessageBox(NULL, lpErrMessage, lpAppTitle, MB_ICONINFORMATION);
353 LocalFree(lpErrMessage);
354 }
355
356 if(lpAppTitle != NULL)
357 {
358 LocalFree(lpAppTitle);
359 }
360
361 if(hWnd == NULL)
362 {
363 HeapFree(hAppHeap, 0, MixerWindow);
364 }
365
366 return hWnd;
367 }
368
369 int WINAPI
370 WinMain(HINSTANCE hInstance,
371 HINSTANCE hPrevInstance,
372 LPSTR lpszCmdLine,
373 int nCmdShow)
374 {
375 MSG Msg;
376
377 hAppInstance = hInstance;
378 hAppHeap = GetProcessHeap();
379
380 InitCommonControls();
381
382 if(!RegisterApplicationClasses())
383 {
384 DBG("Failed to register application classes (LastError: %d)!\n", GetLastError());
385 return 1;
386 }
387
388 hMainWnd = CreateApplicationWindow();
389 if(hMainWnd == NULL)
390 {
391 DBG("Failed to creat application window (LastError: %d)!\n", GetLastError());
392 return 1;
393 }
394
395 while(GetMessage(&Msg, NULL, 0, 0))
396 {
397 TranslateMessage(&Msg);
398 DispatchMessage(&Msg);
399 }
400
401 DestroyWindow(hMainWnd);
402
403 UnregisterApplicationClasses();
404
405 return 0;
406 }
407