2 * ReactOS Sound Volume Control
3 * Copyright (C) 2004-2005 Thomas Weidenmueller
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS Sound Volume Control
22 * FILE: base/applications/sndvol32/sndvol32.c
23 * PROGRAMMERS: Thomas Weidenmueller <w3seek@reactos.com>
30 HINSTANCE hAppInstance
;
35 PREFERENCES_CONTEXT Preferences
;
37 #define GetDialogData(hwndDlg, type) \
38 ( P##type )GetWindowLongPtr((hwndDlg), DWLP_USER)
39 #define GetWindowData(hwnd, type) \
40 ( P##type )GetWindowLongPtr((hwnd), GWL_USERDATA)
42 /******************************************************************************/
46 typedef struct _PREFERENCES_FILL_DEVICES
48 PPREFERENCES_CONTEXT PrefContext
;
51 } PREFERENCES_FILL_DEVICES
, *PPREFERENCES_FILL_DEVICES
;
54 FillDeviceComboBox(PSND_MIXER Mixer
,
60 PPREFERENCES_FILL_DEVICES FillContext
= (PPREFERENCES_FILL_DEVICES
)Context
;
62 UNREFERENCED_PARAMETER(Mixer
);
64 lres
= SendMessage(FillContext
->hComboBox
,
70 /* save the index so we don't screw stuff when the combobox is sorted... */
71 SendMessage(FillContext
->hComboBox
,
76 if (Id
== FillContext
->Selected
)
78 SendMessage(FillContext
->hComboBox
,
89 PrefDlgAddLine(PSND_MIXER Mixer
,
94 PPREFERENCES_CONTEXT PrefContext
= (PPREFERENCES_CONTEXT
)Context
;
96 UNREFERENCED_PARAMETER(Mixer
);
97 UNREFERENCED_PARAMETER(DisplayControls
);
99 switch (Line
->dwComponentType
)
101 case MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
:
102 if (PrefContext
->PlaybackID
== (DWORD
)-1)
104 PrefContext
->PlaybackID
= Line
->dwLineID
;
106 if (PrefContext
->SelectedLine
== (DWORD
)-1)
108 PrefContext
->SelectedLine
= Line
->dwLineID
;
112 goto AddToOthersLines
;
116 case MIXERLINE_COMPONENTTYPE_DST_WAVEIN
:
117 if (PrefContext
->RecordingID
== (DWORD
)-1)
119 PrefContext
->RecordingID
= Line
->dwLineID
;
121 if (PrefContext
->SelectedLine
== (DWORD
)-1)
123 PrefContext
->SelectedLine
= Line
->dwLineID
;
127 goto AddToOthersLines
;
136 if (PrefContext
->SelectedLine
== (DWORD
)-1)
138 PrefContext
->SelectedLine
= Line
->dwLineID
;
142 hwndCbOthers
= GetDlgItem(PrefContext
->hwndDlg
,
145 lres
= SendMessage(hwndCbOthers
,
148 (LPARAM
)Line
->szName
);
151 SendMessage(hwndCbOthers
,
156 PrefContext
->OtherLines
++;
166 PrefDlgAddConnection(PSND_MIXER Mixer
,
171 PPREFERENCES_CONTEXT PrefContext
= (PPREFERENCES_CONTEXT
)Context
;
176 UNREFERENCED_PARAMETER(Mixer
);
177 UNREFERENCED_PARAMETER(LineID
);
179 if (Line
->cControls
!= 0)
181 hwndControls
= GetDlgItem(PrefContext
->hwndDlg
,
184 lvi
.mask
= LVIF_TEXT
| LVIF_PARAM
;
185 lvi
.iItem
= PrefContext
->tmp
++;
187 lvi
.pszText
= Line
->szName
;
188 lvi
.lParam
= (LPARAM
)Line
->dwSource
;
190 i
= SendMessage(hwndControls
,
196 TCHAR LineName
[MIXER_LONG_NAME_CHARS
];
198 BOOL SelLine
= FALSE
;
200 if (SndMixerGetLineName(PrefContext
->Mixer
,
201 PrefContext
->SelectedLine
,
203 MIXER_LONG_NAME_CHARS
,
206 LineName
[0] = TEXT('\0');
209 if (ReadLineConfig(PrefContext
->DeviceName
,
220 ListView_SetCheckState(hwndControls
,
230 UpdatePrefDlgControls(PPREFERENCES_CONTEXT Context
,
233 INT OldID
, MixerID
= 0;
236 /* select the mixer */
237 DeviceCbIndex
= SendDlgItemMessage(Context
->hwndDlg
,
242 if (DeviceCbIndex
!= CB_ERR
)
244 MixerID
= SendDlgItemMessage(Context
->hwndDlg
,
249 if (MixerID
== CB_ERR
)
255 OldID
= Context
->Selected
;
256 if (MixerID
!= OldID
&&
257 SndMixerSelect(Context
->Mixer
,
260 Context
->Selected
= SndMixerGetSelection(Context
->Mixer
);
262 /* update the controls */
263 Context
->PlaybackID
= (DWORD
)-1;
264 Context
->RecordingID
= (DWORD
)-1;
265 Context
->OtherLines
= 0;
266 Context
->SelectedLine
= (DWORD
)-1;
268 SndMixerGetProductName(Context
->Mixer
,
270 sizeof(Context
->DeviceName
) / sizeof(Context
->DeviceName
[0]));
272 if (SndMixerEnumLines(Context
->Mixer
,
278 /* enable/disable controls and make default selection */
279 EnableWindow(GetDlgItem(Context
->hwndDlg
,
281 Context
->PlaybackID
!= (DWORD
)-1);
282 CheckDlgButton(Context
->hwndDlg
,
284 (Context
->PlaybackID
!= (DWORD
)-1 && SelBox
++ == 0) ?
285 BST_CHECKED
: BST_UNCHECKED
);
287 EnableWindow(GetDlgItem(Context
->hwndDlg
,
289 Context
->RecordingID
!= (DWORD
)-1);
290 CheckDlgButton(Context
->hwndDlg
,
292 (Context
->RecordingID
!= (DWORD
)-1 && SelBox
++ == 0) ?
293 BST_CHECKED
: BST_UNCHECKED
);
295 if (Context
->OtherLines
!= 0)
297 /* select the first item in the other lines combo box by default */
298 SendDlgItemMessage(Context
->hwndDlg
,
304 EnableWindow(GetDlgItem(Context
->hwndDlg
,
307 EnableWindow(GetDlgItem(Context
->hwndDlg
,
309 Context
->OtherLines
!= 0);
310 CheckDlgButton(Context
->hwndDlg
,
312 (Context
->OtherLines
!= 0 && SelBox
++ == 0) ?
313 BST_CHECKED
: BST_UNCHECKED
);
315 /* disable the OK button if the device doesn't have any lines */
316 EnableWindow(GetDlgItem(Context
->hwndDlg
,
318 Context
->PlaybackID
!= (DWORD
)-1 ||
319 Context
->RecordingID
!= (DWORD
)-1 ||
320 Context
->OtherLines
!= 0);
322 LineID
= Context
->SelectedLine
;
326 /* update the line sources list */
327 if ((MixerID
!= OldID
&& Context
->SelectedLine
!= (DWORD
)-1) ||
328 (Context
->SelectedLine
!= LineID
&& LineID
!= (DWORD
)-1))
330 Context
->SelectedLine
= LineID
;
332 (void)ListView_DeleteAllItems(GetDlgItem(Context
->hwndDlg
,
336 SndMixerEnumConnections(Context
->Mixer
,
338 PrefDlgAddConnection
,
345 WriteLineSettings(PPREFERENCES_CONTEXT Context
, HWND hwndDlg
)
349 WCHAR LineName
[MIXER_LONG_NAME_CHARS
];
350 WCHAR DestinationName
[MIXER_LONG_NAME_CHARS
];
352 PSNDVOL_REG_LINESTATE LineStates
;
355 hwndControls
= GetDlgItem(hwndDlg
, IDC_CONTROLS
);
357 /* get list item count */
358 Count
= ListView_GetItemCount(hwndControls
);
363 if (SndMixerGetLineName(Context
->Mixer
, Context
->SelectedLine
, DestinationName
, MIXER_LONG_NAME_CHARS
, TRUE
) == -1)
365 /* failed to get destination line name */
369 /* allocate line states array */
370 LineStates
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(SNDVOL_REG_LINESTATE
) * Count
);
371 if (LineStates
== NULL
)
373 /* failed to allocate line states array */
378 for(Index
= 0; Index
< Count
; Index
++)
384 ListView_GetItemText(hwndControls
, Index
, 0, LineName
, MIXER_LONG_NAME_CHARS
);
386 /* make sure it is null terminated */
387 LineName
[MIXER_LONG_NAME_CHARS
-1] = L
'\0';
389 /* get check state */
390 Flags
= (ListView_GetCheckState(hwndControls
, Index
) == 0 ? 0x4 : 0);
393 wcscpy(LineStates
[Index
].LineName
, LineName
);
396 LineStates
[Index
].Flags
= Flags
;
399 /* now write the line config */
400 WriteLineConfig(Context
->DeviceName
, DestinationName
, LineStates
, sizeof(SNDVOL_REG_LINESTATE
) * Count
);
402 /* free line states */
403 HeapFree(GetProcessHeap(), 0, LineStates
);
406 static INT_PTR CALLBACK
407 DlgPreferencesProc(HWND hwndDlg
,
412 PPREFERENCES_CONTEXT Context
;
418 Context
= GetDialogData(hwndDlg
,
419 PREFERENCES_CONTEXT
);
420 switch (LOWORD(wParam
))
422 case IDC_MIXERDEVICE
:
424 if (HIWORD(wParam
) == CBN_SELCHANGE
)
426 UpdatePrefDlgControls(Context
,
434 if (HIWORD(wParam
) == CBN_SELCHANGE
)
439 Index
= SendDlgItemMessage(hwndDlg
,
446 LineID
= SendDlgItemMessage(hwndDlg
,
451 if (LineID
!= CB_ERR
)
453 UpdatePrefDlgControls(Context
,
463 UpdatePrefDlgControls(Context
,
464 Context
->PlaybackID
);
465 EnableWindow(GetDlgItem(hwndDlg
,
473 UpdatePrefDlgControls(Context
,
474 Context
->RecordingID
);
475 EnableWindow(GetDlgItem(hwndDlg
,
486 EnableWindow(GetDlgItem(hwndDlg
,
490 LineCbIndex
= SendDlgItemMessage(hwndDlg
,
495 if (LineCbIndex
!= CB_ERR
)
497 LineID
= SendDlgItemMessage(hwndDlg
,
502 if (LineID
!= CB_ERR
)
504 UpdatePrefDlgControls(Context
,
513 /* write line settings */
514 WriteLineSettings(Context
, hwndDlg
);
530 PREFERENCES_FILL_DEVICES FillDevContext
;
535 SetWindowLongPtr(hwndDlg
,
538 Context
= (PPREFERENCES_CONTEXT
)((LONG_PTR
)lParam
);
539 Context
->hwndDlg
= hwndDlg
;
540 Context
->Mixer
= SndMixerCreate(hwndDlg
, Context
->MixerWindow
->MixerId
);
541 Context
->Selected
= (UINT
)-1;
543 FillDevContext
.PrefContext
= Context
;
544 FillDevContext
.hComboBox
= GetDlgItem(hwndDlg
,
546 FillDevContext
.Selected
= SndMixerGetSelection(Context
->Mixer
);
547 SndMixerEnumProducts(Context
->Mixer
,
551 /* initialize the list view control */
552 hwndControls
= GetDlgItem(hwndDlg
,
554 (void)ListView_SetExtendedListViewStyle(hwndControls
,
557 GetClientRect(hwndControls
,
559 lvc
.mask
= LVCF_TEXT
| LVCF_WIDTH
;
560 lvc
.pszText
= TEXT("");
561 lvc
.cx
= rcClient
.right
;
562 SendMessage(hwndControls
,
567 /* update all controls */
568 UpdatePrefDlgControls(Context
,
569 (DWORD
)Context
->SelectedLine
);
580 case WM_SYSCOLORCHANGE
:
584 /* Forward WM_SYSCOLORCHANGE */
585 hwndControls
= GetDlgItem(hwndDlg
, IDC_CONTROLS
);
586 SendMessage(hwndControls
, WM_SYSCOLORCHANGE
, 0, 0);
595 /******************************************************************************/
598 DeleteMixerWindowControls(PMIXER_WINDOW MixerWindow
)
602 for(Index
= 0; Index
< MixerWindow
->WindowCount
; Index
++)
604 /* destroys the window */
605 DestroyWindow(MixerWindow
->Window
[Index
]);
609 HeapFree(GetProcessHeap(), 0, MixerWindow
->Window
);
612 MixerWindow
->Window
= NULL
;
613 MixerWindow
->WindowCount
= 0;
617 RebuildMixerWindowControls(PPREFERENCES_CONTEXT PrefContext
)
619 /* delete existing mixer controls */
620 DeleteMixerWindowControls(PrefContext
->MixerWindow
);
622 /* load new mixer controls */
623 LoadDialogCtrls(PrefContext
);
631 SetVolumeCallback(PSND_MIXER Mixer
, DWORD LineID
, LPMIXERLINE Line
, PVOID Ctx
)
633 UINT ControlCount
= 0, Index
;
634 LPMIXERCONTROL Control
= NULL
;
635 PMIXERCONTROLDETAILS_UNSIGNED puDetails
= NULL
;
636 MIXERCONTROLDETAILS_BOOLEAN bDetails
;
637 PSET_VOLUME_CONTEXT Context
= (PSET_VOLUME_CONTEXT
)Ctx
;
639 /* check if the line name is equal */
640 if (wcsicmp(Line
->szName
, Context
->LineName
))
647 if (SndMixerQueryControls(Mixer
, &ControlCount
, Line
, &Control
) == FALSE
)
649 /* failed to query for controls */
653 puDetails
= HeapAlloc(GetProcessHeap(), 0, Line
->cChannels
* sizeof(MIXERCONTROLDETAILS_UNSIGNED
));
654 if (puDetails
== NULL
)
657 /* now go through all controls and compare control ids */
658 for (Index
= 0; Index
< ControlCount
; Index
++)
660 if (Context
->bVertical
)
662 if ((Control
[Index
].dwControlType
& MIXERCONTROL_CT_CLASS_MASK
) == MIXERCONTROL_CT_CLASS_FADER
)
664 DWORD LineOffset
, volumePosition
, balancePosition
;
665 DWORD volumeStep
, balanceStep
;
667 LineOffset
= Context
->SliderPos
;
669 volumePosition
= (DWORD
)SendDlgItemMessage(Preferences
.MixerWindow
->hWnd
, LineOffset
* IDC_LINE_SLIDER_VERT
, TBM_GETPOS
, 0, 0);
670 volumeStep
= (Control
[Index
].Bounds
.dwMaximum
- Control
[Index
].Bounds
.dwMinimum
) / (VOLUME_MAX
- VOLUME_MIN
);
672 if (Line
->cChannels
== 1)
675 puDetails
[0].dwValue
= ((VOLUME_MAX
- volumePosition
) * volumeStep
) + Control
[Index
].Bounds
.dwMinimum
;
677 else if (Line
->cChannels
== 2)
679 balancePosition
= (DWORD
)SendDlgItemMessage(Preferences
.MixerWindow
->hWnd
, LineOffset
* IDC_LINE_SLIDER_HORZ
, TBM_GETPOS
, 0, 0);
680 if (balancePosition
== BALANCE_CENTER
)
682 puDetails
[0].dwValue
= ((VOLUME_MAX
- volumePosition
) * volumeStep
) + Control
[Index
].Bounds
.dwMinimum
;
683 puDetails
[1].dwValue
= ((VOLUME_MAX
- volumePosition
) * volumeStep
) + Control
[Index
].Bounds
.dwMinimum
;
685 else if (balancePosition
== BALANCE_LEFT
)
687 puDetails
[0].dwValue
= ((VOLUME_MAX
- volumePosition
) * volumeStep
) + Control
[Index
].Bounds
.dwMinimum
;
688 puDetails
[1].dwValue
= Control
[Index
].Bounds
.dwMinimum
;
690 else if (balancePosition
== BALANCE_RIGHT
)
692 puDetails
[0].dwValue
= Control
[Index
].Bounds
.dwMinimum
;
693 puDetails
[1].dwValue
= ((VOLUME_MAX
- volumePosition
) * volumeStep
) + Control
[Index
].Bounds
.dwMinimum
;
695 else if (balancePosition
< BALANCE_CENTER
) // Left
697 puDetails
[0].dwValue
= ((VOLUME_MAX
- volumePosition
) * volumeStep
) + Control
[Index
].Bounds
.dwMinimum
;
699 balanceStep
= (puDetails
[0].dwValue
- Control
[Index
].Bounds
.dwMinimum
) / (BALANCE_STEPS
/ 2);
701 puDetails
[1].dwValue
= (balancePosition
* balanceStep
) + Control
[Index
].Bounds
.dwMinimum
;
703 else if (balancePosition
> BALANCE_CENTER
) // Right
705 puDetails
[1].dwValue
= ((VOLUME_MAX
- volumePosition
) * volumeStep
) + Control
[Index
].Bounds
.dwMinimum
;
707 balanceStep
= (puDetails
[1].dwValue
- Control
[Index
].Bounds
.dwMinimum
) / (BALANCE_STEPS
/ 2);
709 puDetails
[0].dwValue
= ((BALANCE_RIGHT
- balancePosition
) * balanceStep
) + Control
[Index
].Bounds
.dwMinimum
;
714 SndMixerGetVolumeControlDetails(Preferences
.MixerWindow
->Mixer
, Control
[Index
].dwControlID
, Line
->cChannels
, sizeof(MIXERCONTROLDETAILS_UNSIGNED
), (LPVOID
)puDetails
);
720 SndMixerSetVolumeControlDetails(Preferences
.MixerWindow
->Mixer
, Control
[Index
].dwControlID
, Line
->cChannels
, sizeof(MIXERCONTROLDETAILS_UNSIGNED
), (LPVOID
)puDetails
);
726 else if (Context
->bSwitch
)
728 if ((Control
[Index
].dwControlType
& MIXERCONTROL_CT_CLASS_MASK
) == MIXERCONTROL_CT_CLASS_SWITCH
)
731 bDetails
.fValue
= Context
->SliderPos
;
734 SndMixerSetVolumeControlDetails(Preferences
.MixerWindow
->Mixer
, Control
[Index
].dwControlID
, 1, sizeof(MIXERCONTROLDETAILS_BOOLEAN
), (LPVOID
)&bDetails
);
742 if (puDetails
!= NULL
)
743 HeapFree(GetProcessHeap(), 0, puDetails
);
746 HeapFree(GetProcessHeap(), 0, Control
);
756 MixerControlChangeCallback(PSND_MIXER Mixer
, DWORD LineID
, LPMIXERLINE Line
, PVOID Context
)
758 PMIXERCONTROLDETAILS_UNSIGNED pVolumeDetails
= NULL
;
759 UINT ControlCount
= 0, Index
;
760 LPMIXERCONTROL Control
= NULL
;
762 /* check if the line has controls */
763 if (Line
->cControls
== 0)
770 if (SndMixerQueryControls(Mixer
, &ControlCount
, Line
, &Control
) == FALSE
)
772 /* failed to query for controls */
776 pVolumeDetails
= HeapAlloc(GetProcessHeap(),
778 Line
->cChannels
* sizeof(MIXERCONTROLDETAILS_UNSIGNED
));
779 if (pVolumeDetails
== NULL
)
782 /* now go through all controls and compare control ids */
783 for (Index
= 0; Index
< ControlCount
; Index
++)
785 if (Control
[Index
].dwControlID
== PtrToUlong(Context
))
787 if ((Control
[Index
].dwControlType
& MIXERCONTROL_CT_CLASS_MASK
) == MIXERCONTROL_CT_CLASS_SWITCH
)
789 MIXERCONTROLDETAILS_BOOLEAN Details
;
791 /* get volume control details */
792 if (SndMixerGetVolumeControlDetails(Preferences
.MixerWindow
->Mixer
, Control
[Index
].dwControlID
, 1, sizeof(MIXERCONTROLDETAILS_BOOLEAN
), (LPVOID
)&Details
) != -1)
794 /* update dialog control */
795 UpdateDialogLineSwitchControl(&Preferences
, Line
, Details
.fValue
);
798 else if ((Control
[Index
].dwControlType
& MIXERCONTROL_CT_CLASS_MASK
) == MIXERCONTROL_CT_CLASS_FADER
)
800 /* get volume control details */
801 if (SndMixerGetVolumeControlDetails(Preferences
.MixerWindow
->Mixer
, Control
[Index
].dwControlID
, Line
->cChannels
, sizeof(MIXERCONTROLDETAILS_UNSIGNED
), (LPVOID
)pVolumeDetails
) != -1)
803 /* update dialog control */
804 DWORD volumePosition
, volumeStep
, maxVolume
, i
;
805 DWORD balancePosition
, balanceStep
;
807 volumeStep
= (Control
[Index
].Bounds
.dwMaximum
- Control
[Index
].Bounds
.dwMinimum
) / (VOLUME_MAX
- VOLUME_MIN
);
810 for (i
= 0; i
< Line
->cChannels
; i
++)
812 if (pVolumeDetails
[i
].dwValue
> maxVolume
)
813 maxVolume
= pVolumeDetails
[i
].dwValue
;
816 volumePosition
= (maxVolume
- Control
[Index
].Bounds
.dwMinimum
) / volumeStep
;
818 if (Line
->cChannels
== 1)
820 balancePosition
= BALANCE_CENTER
;
822 else if (Line
->cChannels
== 2)
824 if (pVolumeDetails
[0].dwValue
== pVolumeDetails
[1].dwValue
)
826 balancePosition
= BALANCE_CENTER
;
828 else if (pVolumeDetails
[0].dwValue
== Control
[Index
].Bounds
.dwMinimum
)
830 balancePosition
= BALANCE_RIGHT
;
832 else if (pVolumeDetails
[1].dwValue
== Control
[Index
].Bounds
.dwMinimum
)
834 balancePosition
= BALANCE_LEFT
;
838 balanceStep
= (maxVolume
- Control
[Index
].Bounds
.dwMinimum
) / (BALANCE_STEPS
/ 2);
840 if (pVolumeDetails
[0].dwValue
< pVolumeDetails
[1].dwValue
)
842 balancePosition
= (pVolumeDetails
[0].dwValue
- Control
[Index
].Bounds
.dwMinimum
) / balanceStep
;
843 balancePosition
= BALANCE_RIGHT
- balancePosition
;
845 else if (pVolumeDetails
[1].dwValue
< pVolumeDetails
[0].dwValue
)
847 balancePosition
= (pVolumeDetails
[1].dwValue
- Control
[Index
].Bounds
.dwMinimum
) / balanceStep
;
848 balancePosition
= BALANCE_LEFT
+ balancePosition
;
853 /* Update the volume control slider */
854 UpdateDialogLineSliderControl(&Preferences
, Line
, IDC_LINE_SLIDER_VERT
, VOLUME_MAX
- volumePosition
);
856 /* Update the balance control slider */
857 UpdateDialogLineSliderControl(&Preferences
, Line
, IDC_LINE_SLIDER_HORZ
, balancePosition
);
865 /* Free the volume details */
867 HeapFree(GetProcessHeap(), 0, pVolumeDetails
);
870 HeapFree(GetProcessHeap(), 0, Control
);
879 PMIXER_WINDOW MixerWindow
)
886 if (MixerWindow
->Mode
!= NORMAL_MODE
)
889 if (MixerWindow
->bHasExtendedControls
== FALSE
)
892 if (MixerWindow
->hStatusBar
)
894 GetWindowRect(MixerWindow
->hStatusBar
, &statusRect
);
897 /* Height of the 'Advanced' button in dialog units plus 2 units bottom space */
898 #define BUTTON_HEIGHT 16
899 dy
= MulDiv(BUTTON_HEIGHT
, MixerWindow
->baseUnit
.cy
, 8);
901 if (MixerWindow
->bShowExtendedControls
)
902 MixerWindow
->rect
.bottom
+= dy
;
904 MixerWindow
->rect
.bottom
-= dy
;
906 SetWindowPos(MixerWindow
->hWnd
,
908 MixerWindow
->rect
.left
,
909 MixerWindow
->rect
.top
,
910 MixerWindow
->rect
.right
- MixerWindow
->rect
.left
,
911 MixerWindow
->rect
.bottom
- MixerWindow
->rect
.top
,
912 SWP_NOMOVE
| SWP_NOZORDER
);
914 if (MixerWindow
->hStatusBar
)
916 SetWindowPos(MixerWindow
->hStatusBar
,
919 MixerWindow
->rect
.bottom
- (statusRect
.bottom
- statusRect
.top
),
920 MixerWindow
->rect
.right
- MixerWindow
->rect
.left
,
921 statusRect
.bottom
- statusRect
.top
,
925 for (i
= 0; i
< MixerWindow
->DialogCount
; i
++)
927 hDlgCtrl
= GetDlgItem(MixerWindow
->hWnd
, IDC_LINE_SEP
* i
);
928 if (hDlgCtrl
!= NULL
)
930 GetWindowRect(hDlgCtrl
, &statusRect
);
931 if (MixerWindow
->bShowExtendedControls
)
932 statusRect
.bottom
+= dy
;
934 statusRect
.bottom
-= dy
;
936 SetWindowPos(hDlgCtrl
,
940 statusRect
.right
- statusRect
.left
,
941 statusRect
.bottom
- statusRect
.top
,
942 SWP_NOMOVE
| SWP_NOZORDER
);
948 static LRESULT CALLBACK
949 MainWindowProc(HWND hwnd
,
954 PMIXER_WINDOW MixerWindow
;
955 DWORD CtrlID
, LineOffset
;
957 SET_VOLUME_CONTEXT Context
;
963 MixerWindow
= GetWindowData(hwnd
,
966 switch (LOWORD(wParam
))
970 PREFERENCES_CONTEXT Pref
;
972 Pref
.MixerWindow
= MixerWindow
;
974 Pref
.SelectedLine
= Preferences
.SelectedLine
;
976 if (DialogBoxParam(hAppInstance
,
977 MAKEINTRESOURCE(IDD_PREFERENCES
),
980 (LPARAM
)&Pref
) == IDOK
)
983 TCHAR szProduct
[MAXPNAMELEN
];
985 /* get mixer product name */
986 if (SndMixerGetProductName(Pref
.Mixer
,
988 sizeof(szProduct
) / sizeof(szProduct
[0])) == -1)
990 /* failed to get name */
991 szProduct
[0] = L
'\0';
996 wcscpy(Preferences
.DeviceName
, szProduct
);
999 /* destroy old status bar */
1000 if (MixerWindow
->Mode
== NORMAL_MODE
)
1001 DestroyWindow(MixerWindow
->hStatusBar
);
1003 /* update details */
1004 Preferences
.SelectedLine
= Pref
.SelectedLine
;
1006 /* destroy old mixer */
1007 SndMixerDestroy(Preferences
.MixerWindow
->Mixer
);
1009 /* use new selected mixer */
1010 Preferences
.MixerWindow
->Mixer
= Pref
.Mixer
;
1012 /* create status window */
1013 if (MixerWindow
->Mode
== NORMAL_MODE
)
1015 MixerWindow
->hStatusBar
= CreateStatusWindow(WS_VISIBLE
| WS_CHILD
| WS_CLIPSIBLINGS
,
1019 if (MixerWindow
->hStatusBar
)
1021 /* Set status bar */
1022 SendMessage(MixerWindow
->hStatusBar
,
1029 /* rebuild dialog controls */
1030 RebuildMixerWindowControls(&Preferences
);
1035 case IDM_ADVANCED_CONTROLS
:
1036 MixerWindow
->bShowExtendedControls
= !MixerWindow
->bShowExtendedControls
;
1037 CheckMenuItem(GetMenu(hwnd
),
1038 IDM_ADVANCED_CONTROLS
,
1039 MF_BYCOMMAND
| (MixerWindow
->bShowExtendedControls
? MF_CHECKED
: MF_UNCHECKED
));
1040 ResizeMixerWindow(MixerWindow
);
1051 HICON hAppIcon
= (HICON
)GetClassLongPtrW(hwnd
,
1063 CtrlID
= LOWORD(wParam
);
1065 /* check if the message is from the line switch */
1066 if (HIWORD(wParam
) == BN_CLICKED
&& (CtrlID
% IDC_LINE_SWITCH
== 0))
1068 /* compute line offset */
1069 LineOffset
= CtrlID
/ IDC_LINE_SWITCH
;
1071 /* compute window id of line name static control */
1072 CtrlID
= LineOffset
* IDC_LINE_NAME
;
1075 if (GetDlgItemTextW(hwnd
, CtrlID
, Context
.LineName
, MIXER_LONG_NAME_CHARS
) != 0)
1078 Context
.SliderPos
= SendMessage((HWND
)lParam
, BM_GETCHECK
, 0, 0);
1079 Context
.bVertical
= FALSE
;
1080 Context
.bSwitch
= TRUE
;
1083 SndMixerEnumConnections(Preferences
.MixerWindow
->Mixer
, Preferences
.SelectedLine
, SetVolumeCallback
, (LPVOID
)&Context
);
1092 case MM_MIXM_LINE_CHANGE
:
1094 DPRINT("MM_MIXM_LINE_CHANGE\n");
1098 case MM_MIXM_CONTROL_CHANGE
:
1100 DPRINT("MM_MIXM_CONTROL_CHANGE\n");
1102 /* get mixer window */
1103 MixerWindow
= GetWindowData(hwnd
,
1107 assert(MixerWindow
);
1108 assert(MixerWindow
->Mixer
->hmx
== (HMIXER
)wParam
);
1110 SndMixerEnumConnections(MixerWindow
->Mixer
, Preferences
.SelectedLine
, MixerControlChangeCallback
, (PVOID
)lParam
);
1115 switch (LOWORD(wParam
))
1118 /* get dialog item ctrl */
1119 CtrlID
= GetDlgCtrlID((HWND
)lParam
);
1121 /* get line index */
1122 LineOffset
= CtrlID
/ IDC_LINE_SLIDER_VERT
;
1124 /* compute window id of line name static control */
1125 CtrlID
= LineOffset
* IDC_LINE_NAME
;
1128 if (GetDlgItemTextW(hwnd
, CtrlID
, Context
.LineName
, MIXER_LONG_NAME_CHARS
) != 0)
1131 Context
.SliderPos
= LineOffset
;
1132 Context
.bVertical
= TRUE
;
1133 Context
.bSwitch
= FALSE
;
1136 SndMixerEnumConnections(Preferences
.MixerWindow
->Mixer
, Preferences
.SelectedLine
, SetVolumeCallback
, (LPVOID
)&Context
);
1141 MixerWindow
= GetWindowData(hwnd
,
1144 /* get dialog item ctrl */
1145 CtrlID
= GetDlgCtrlID((HWND
)lParam
);
1147 /* get line index */
1148 LineOffset
= CtrlID
/ IDC_LINE_SLIDER_VERT
;
1150 if (LineOffset
== 1 && MixerWindow
->Mixer
->MixerId
== 0)
1151 PlaySound((LPCTSTR
)SND_ALIAS_SYSTEMDEFAULT
, NULL
, SND_ASYNC
| SND_ALIAS_ID
);
1160 switch (LOWORD(wParam
))
1163 /* get dialog item ctrl */
1164 CtrlID
= GetDlgCtrlID((HWND
)lParam
);
1166 /* get line index */
1167 LineOffset
= CtrlID
/ IDC_LINE_SLIDER_HORZ
;
1169 /* compute window id of line name static control */
1170 CtrlID
= LineOffset
* IDC_LINE_NAME
;
1173 if (GetDlgItemTextW(hwnd
, CtrlID
, Context
.LineName
, MIXER_LONG_NAME_CHARS
) != 0)
1176 Context
.SliderPos
= LineOffset
;
1177 Context
.bVertical
= TRUE
;
1178 Context
.bSwitch
= FALSE
;
1181 SndMixerEnumConnections(Preferences
.MixerWindow
->Mixer
, Preferences
.SelectedLine
, SetVolumeCallback
, (LPVOID
)&Context
);
1186 MixerWindow
= GetWindowData(hwnd
,
1189 /* get dialog item ctrl */
1190 CtrlID
= GetDlgCtrlID((HWND
)lParam
);
1192 /* get line index */
1193 LineOffset
= CtrlID
/ IDC_LINE_SLIDER_HORZ
;
1195 if (LineOffset
== 1 && MixerWindow
->Mixer
->MixerId
== 0)
1196 PlaySound((LPCTSTR
)SND_ALIAS_SYSTEMDEFAULT
, NULL
, SND_ASYNC
| SND_ALIAS_ID
);
1207 MixerWindow
= ((LPCREATESTRUCT
)lParam
)->lpCreateParams
;
1208 SetWindowLongPtr(hwnd
,
1210 (LONG_PTR
)MixerWindow
);
1211 MixerWindow
->hWnd
= hwnd
;
1212 MixerWindow
->Mixer
= SndMixerCreate(MixerWindow
->hWnd
, MixerWindow
->MixerId
);
1213 if (MixerWindow
->Mixer
!= NULL
)
1215 TCHAR szProduct
[MAXPNAMELEN
];
1217 /* get mixer product name */
1218 if (SndMixerGetProductName(MixerWindow
->Mixer
,
1220 sizeof(szProduct
) / sizeof(szProduct
[0])) == -1)
1222 /* failed to get name */
1223 szProduct
[0] = L
'\0';
1227 /* initialize preferences */
1228 ZeroMemory(&Preferences
, sizeof(Preferences
));
1231 Preferences
.Mixer
= MixerWindow
->Mixer
;
1233 /* store mixer window */
1234 Preferences
.MixerWindow
= MixerWindow
;
1236 /* first destination line id */
1237 Preferences
.SelectedLine
= 0xFFFF0000;
1240 wcscpy(Preferences
.DeviceName
, szProduct
);
1242 /* Disable the 'Advanced Controls' menu item */
1243 EnableMenuItem(GetMenu(hwnd
), IDM_ADVANCED_CONTROLS
, MF_BYCOMMAND
| MF_GRAYED
);
1245 /* create status window */
1246 if (MixerWindow
->Mode
== NORMAL_MODE
)
1248 MixerWindow
->hStatusBar
= CreateStatusWindow(WS_VISIBLE
| WS_CHILD
| WS_CLIPSIBLINGS
,
1252 if (MixerWindow
->hStatusBar
)
1254 SendMessage(MixerWindow
->hStatusBar
,
1261 if (!RebuildMixerWindowControls(&Preferences
))
1263 DPRINT("Rebuilding mixer window controls failed!\n");
1264 SndMixerDestroy(MixerWindow
->Mixer
);
1265 MixerWindow
->Mixer
= NULL
;
1274 MixerWindow
= GetWindowData(hwnd
,
1276 if (MixerWindow
!= NULL
)
1278 if (MixerWindow
->Mixer
!= NULL
)
1280 SndMixerDestroy(MixerWindow
->Mixer
);
1282 if (MixerWindow
->hFont
)
1283 DeleteObject(MixerWindow
->hFont
);
1284 HeapFree(hAppHeap
, 0, MixerWindow
);
1297 Result
= DefWindowProc(hwnd
,
1309 RegisterApplicationClasses(VOID
)
1313 wc
.cbSize
= sizeof(WNDCLASSEX
);
1314 wc
.style
= CS_HREDRAW
| CS_VREDRAW
;
1315 wc
.lpfnWndProc
= MainWindowProc
;
1317 wc
.cbWndExtra
= sizeof(PMIXER_WINDOW
);
1318 wc
.hInstance
= hAppInstance
;
1319 wc
.hIcon
= LoadIcon(hAppInstance
,
1320 MAKEINTRESOURCE(IDI_MAINAPP
));
1321 wc
.hCursor
= LoadCursor(NULL
,
1323 wc
.hbrBackground
= (HBRUSH
)(COLOR_BTNFACE
+ 1);
1324 wc
.lpszMenuName
= NULL
;
1325 wc
.lpszClassName
= SZ_APP_CLASS
;
1327 MainWindowClass
= RegisterClassEx(&wc
);
1329 return MainWindowClass
!= 0;
1333 UnregisterApplicationClasses(VOID
)
1335 UnregisterClass(SZ_APP_CLASS
,
1340 CreateApplicationWindow(
1341 WINDOW_MODE WindowMode
,
1346 PMIXER_WINDOW MixerWindow
= HeapAlloc(hAppHeap
,
1348 sizeof(MIXER_WINDOW
));
1349 if (MixerWindow
== NULL
)
1354 MixerWindow
->Mode
= WindowMode
;
1355 MixerWindow
->MixerId
= MixerId
;
1357 if (mixerGetNumDevs() > 0)
1359 hWnd
= CreateWindowEx(WS_EX_WINDOWEDGE
| WS_EX_CONTROLPARENT
,
1362 WS_DLGFRAME
| WS_CAPTION
| WS_MINIMIZEBOX
| WS_SYSMENU
| WS_CLIPCHILDREN
| WS_CLIPSIBLINGS
| WS_VISIBLE
,
1365 LoadMenu(hAppInstance
,
1366 MAKEINTRESOURCE(IDM_MAINMENU
)),
1372 LPTSTR lpErrMessage
;
1375 * no mixer devices are available!
1379 if (AllocAndLoadString(&lpErrMessage
,
1381 IDS_NOMIXERDEVICES
))
1386 MB_ICONINFORMATION
);
1387 LocalFree(lpErrMessage
);
1403 HandleCommandLine(LPTSTR cmdline
,
1410 *pMixerId
= PLAY_MIXER
;
1411 *pMode
= (dwStyle
& 0x20) ? SMALL_MODE
: NORMAL_MODE
;
1413 while (*cmdline
== _T(' ') || *cmdline
== _T('-') || *cmdline
== _T('/'))
1415 if (*cmdline
++ == _T(' '))
1421 while (*cmdline
== _T(' '))
1426 case 'd': /* Device */
1430 case 'n': /* Small size */
1432 *pMode
= NORMAL_MODE
;
1435 case 's': /* Small size */
1437 *pMode
= SMALL_MODE
;
1440 case 't': /* Tray size */
1445 case 'p': /* Play mode */
1447 *pMixerId
= PLAY_MIXER
;
1450 case 'r': /* Record mode */
1452 *pMixerId
= RECORD_MIXER
;
1464 _tWinMain(HINSTANCE hInstance
,
1465 HINSTANCE hPrevInstance
,
1471 INITCOMMONCONTROLSEX Controls
;
1472 WINDOW_MODE WindowMode
= SMALL_MODE
;
1476 UNREFERENCED_PARAMETER(hPrevInstance
);
1477 UNREFERENCED_PARAMETER(nCmdShow
);
1479 hAppInstance
= hInstance
;
1480 hAppHeap
= GetProcessHeap();
1482 if (InitAppConfig())
1484 dwStyle
= GetStyleValue();
1485 HandleCommandLine(lpszCmdLine
, dwStyle
, &WindowMode
, &MixerId
);
1487 /* load the application title */
1488 if (!AllocAndLoadString(&lpAppTitle
,
1495 Controls
.dwSize
= sizeof(INITCOMMONCONTROLSEX
);
1496 Controls
.dwICC
= ICC_BAR_CLASSES
| ICC_STANDARD_CLASSES
;
1498 InitCommonControlsEx(&Controls
);
1500 if (WindowMode
== TRAY_MODE
)
1502 DialogBoxParam(hAppInstance
,
1503 MAKEINTRESOURCE(IDD_TRAY_MASTER
),
1510 if (RegisterApplicationClasses())
1512 hMainWnd
= CreateApplicationWindow(WindowMode
, MixerId
);
1513 if (hMainWnd
!= NULL
)
1516 while ((bRet
=GetMessage(&Msg
,
1523 TranslateMessage(&Msg
);
1524 DispatchMessage(&Msg
);
1528 DestroyWindow(hMainWnd
);
1533 DPRINT("Failed to create application window (LastError: %d)!\n", GetLastError());
1536 UnregisterApplicationClasses();
1540 DPRINT("Failed to register application classes (LastError: %d)!\n", GetLastError());
1544 if (lpAppTitle
!= NULL
)
1546 LocalFree(lpAppTitle
);
1553 DPRINT("Unable to open the Volume Control registry key!\n");