* PURPOSE: ReactOS Multimedia Control Panel
* PROGRAMMER: Thomas Weidenmueller <w3seek@reactos.com>
* Johannes Anderwald <janderwald@reactos.com>
+ * Dmitry Chapyshev <dmitry@reactos.org>
*/
#include <windows.h>
#include "mmsys.h"
#include "resource.h"
+#define VOLUME_DIVIDER 0xFFF
+
typedef struct _IMGINFO
{
HBITMAP hBitmap;
} IMGINFO, *PIMGINFO;
+typedef struct _GLOBAL_DATA
+{
+ HMIXER hMixer;
+ HICON hIconMuted;
+ HICON hIconUnMuted;
+
+ LONG muteVal;
+ DWORD muteControlID;
+
+ DWORD volumeControlID;
+ DWORD volumeMinimum;
+ DWORD volumeMaximum;
+ DWORD volumeValue;
+
+} GLOBAL_DATA, *PGLOBAL_DATA;
+
+
static VOID
InitImageInfo(PIMGINFO ImgInfo)
{
}
}
-void
-InitVolumeControls(HWND hwndDlg)
+VOID
+GetMuteControl(PGLOBAL_DATA pGlobalData)
+{
+ MIXERLINE mxln;
+ MIXERCONTROL mxc;
+ MIXERLINECONTROLS mxlctrl;
+
+ if (pGlobalData->hMixer == NULL)
+ return;
+
+ mxln.cbStruct = sizeof(MIXERLINE);
+ mxln.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
+
+ if (mixerGetLineInfo((HMIXEROBJ)pGlobalData->hMixer, &mxln, MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_COMPONENTTYPE)
+ != MMSYSERR_NOERROR) return;
+
+ mxlctrl.cbStruct = sizeof(MIXERLINECONTROLS);
+ mxlctrl.dwLineID = mxln.dwLineID;
+ mxlctrl.dwControlType = MIXERCONTROL_CONTROLTYPE_MUTE;
+ mxlctrl.cControls = 1;
+ mxlctrl.cbmxctrl = sizeof(MIXERCONTROL);
+ mxlctrl.pamxctrl = &mxc;
+
+ if (mixerGetLineControls((HMIXEROBJ)pGlobalData->hMixer, &mxlctrl, MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE)
+ != MMSYSERR_NOERROR) return;
+
+ pGlobalData->muteControlID = mxc.dwControlID;
+}
+
+VOID
+GetMuteState(PGLOBAL_DATA pGlobalData)
+{
+ MIXERCONTROLDETAILS_BOOLEAN mxcdMute;
+ MIXERCONTROLDETAILS mxcd;
+
+ if (pGlobalData->hMixer == NULL)
+ return;
+
+ mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
+ mxcd.dwControlID = pGlobalData->muteControlID;
+ mxcd.cChannels = 1;
+ mxcd.cMultipleItems = 0;
+ mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
+ mxcd.paDetails = &mxcdMute;
+
+ if (mixerGetControlDetails((HMIXEROBJ)pGlobalData->hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_GETCONTROLDETAILSF_VALUE)
+ != MMSYSERR_NOERROR)
+ return;
+
+ pGlobalData->muteVal = mxcdMute.fValue;
+}
+
+VOID
+SwitchMuteState(PGLOBAL_DATA pGlobalData)
+{
+ MIXERCONTROLDETAILS_BOOLEAN mxcdMute;
+ MIXERCONTROLDETAILS mxcd;
+
+ mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
+ mxcd.dwControlID = pGlobalData->muteControlID;
+ mxcd.cChannels = 1;
+ mxcd.cMultipleItems = 0;
+ mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
+ mxcd.paDetails = &mxcdMute;
+
+ mxcdMute.fValue = !pGlobalData->muteVal;
+ if (mixerSetControlDetails((HMIXEROBJ)pGlobalData->hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE)
+ != MMSYSERR_NOERROR)
+ return;
+
+ pGlobalData->muteVal = mxcdMute.fValue;
+}
+
+VOID
+GetVolumeControl(PGLOBAL_DATA pGlobalData)
{
- UINT NumWavOut;
- WAVEOUTCAPS woc;
- MMRESULT errcode;
- DWORD dwDeviceID;
- DWORD dwStatus;
-
- NumWavOut = waveOutGetNumDevs();
- if (!NumWavOut)
+ MIXERLINE mxln;
+ MIXERCONTROL mxc;
+ MIXERLINECONTROLS mxlc;
+
+ if (pGlobalData->hMixer == NULL)
+ return;
+
+ mxln.cbStruct = sizeof(MIXERLINE);
+ mxln.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
+ if (mixerGetLineInfo((HMIXEROBJ)pGlobalData->hMixer, &mxln, MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_COMPONENTTYPE)
+ != MMSYSERR_NOERROR)
+ return;
+
+ mxlc.cbStruct = sizeof(MIXERLINECONTROLS);
+ mxlc.dwLineID = mxln.dwLineID;
+ mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
+ mxlc.cControls = 1;
+ mxlc.cbmxctrl = sizeof(MIXERCONTROL);
+ mxlc.pamxctrl = &mxc;
+ if (mixerGetLineControls((HMIXEROBJ)pGlobalData->hMixer, &mxlc, MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE)
+ != MMSYSERR_NOERROR)
+ return;
+
+ pGlobalData->volumeMinimum = mxc.Bounds.dwMinimum;
+ pGlobalData->volumeMaximum = mxc.Bounds.dwMaximum;
+ pGlobalData->volumeControlID = mxc.dwControlID;
+}
+
+VOID
+GetVolumeValue(PGLOBAL_DATA pGlobalData)
+{
+ MIXERCONTROLDETAILS_UNSIGNED mxcdVolume;
+ MIXERCONTROLDETAILS mxcd;
+
+ if (pGlobalData->hMixer == NULL)
+ return;
+
+ mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
+ mxcd.dwControlID = pGlobalData->volumeControlID;
+ mxcd.cChannels = 1;
+ mxcd.cMultipleItems = 0;
+ mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
+ mxcd.paDetails = &mxcdVolume;
+
+ if (mixerGetControlDetails((HMIXEROBJ)pGlobalData->hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_GETCONTROLDETAILSF_VALUE)
+ != MMSYSERR_NOERROR)
+ return;
+
+ pGlobalData->volumeValue = mxcdVolume.dwValue;
+}
+
+VOID
+SetVolumeValue(PGLOBAL_DATA pGlobalData){
+ MIXERCONTROLDETAILS_UNSIGNED mxcdVolume;
+ MIXERCONTROLDETAILS mxcd;
+
+ if (pGlobalData->hMixer == NULL)
+ return;
+
+ mxcdVolume.dwValue = pGlobalData->volumeValue;
+ mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
+ mxcd.dwControlID = pGlobalData->volumeControlID;
+ mxcd.cChannels = 1;
+ mxcd.cMultipleItems = 0;
+ mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
+ mxcd.paDetails = &mxcdVolume;
+
+ if (mixerSetControlDetails((HMIXEROBJ)pGlobalData->hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE)
+ != MMSYSERR_NOERROR)
+ return;
+
+ pGlobalData->volumeValue = mxcdVolume.dwValue;
+}
+
+
+VOID
+InitVolumeControls(HWND hwndDlg, PGLOBAL_DATA pGlobalData)
+{
+ UINT NumMixers;
+ MIXERCAPS mxc;
+
+ NumMixers = mixerGetNumDevs();
+ if (!NumMixers)
{
- //FIXME
- // deactivate all controls
+ EnableWindow(GetDlgItem(hwndDlg, IDC_VOLUME_TRACKBAR), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_MUTE_CHECKBOX), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ICON_IN_TASKBAR), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ADVANCED_BTN), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SPEAKER_SET_BTN), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SPEAKER_VOL_BTN), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ADVANCED2_BTN), FALSE);
return;
}
- errcode = waveOutMessage((HWAVEOUT)WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET, (DWORD_PTR)&dwDeviceID, (DWORD_PTR)&dwStatus);
- if (errcode != MMSYSERR_NOERROR)
+ if (mixerOpen(&pGlobalData->hMixer, 0, PtrToUlong(hwndDlg), 0, MIXER_OBJECTF_MIXER | CALLBACK_WINDOW) != MMSYSERR_NOERROR)
{
- MessageBox(hwndDlg, _T("Failed to enumerate default device"), NULL, MB_OK);
+ MessageBox(hwndDlg, _T("Cannot open mixer"), NULL, MB_OK);
return;
}
- if (waveOutGetDevCaps(dwDeviceID, &woc, sizeof(WAVEOUTCAPS)) != MMSYSERR_NOERROR)
+ ZeroMemory(&mxc, sizeof(MIXERCAPS));
+ if (mixerGetDevCaps(PtrToUint(pGlobalData->hMixer), &mxc, sizeof(MIXERCAPS)) != MMSYSERR_NOERROR)
{
- MessageBox(hwndDlg, _T("waveOutGetDevCaps failed"), NULL, MB_OK);
+ MessageBox(hwndDlg, _T("mixerGetDevCaps failed"), NULL, MB_OK);
return;
}
- SendDlgItemMessage(hwndDlg, IDC_DEVICE_NAME, WM_SETTEXT, (WPARAM)0, (LPARAM)woc.szPname);
-
- if (!(woc.dwSupport & WAVECAPS_VOLUME))
+ GetMuteControl(pGlobalData);
+ GetMuteState(pGlobalData);
+ if (pGlobalData->muteVal)
{
- /// the device does not support volume changes
- /// disable volume control
- EnableWindow(GetDlgItem(hwndDlg, IDC_VOLUME_TRACKBAR), FALSE);
+ SendDlgItemMessage(hwndDlg, IDC_MUTE_CHECKBOX, BM_SETCHECK, (WPARAM)BST_CHECKED, (LPARAM)0);
+ SendDlgItemMessage(hwndDlg, IDC_MUTE_ICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)pGlobalData->hIconMuted);
}
else
{
- SendDlgItemMessage(hwndDlg, IDC_VOLUME_TRACKBAR, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(0, 10));
- SendDlgItemMessage(hwndDlg, IDC_VOLUME_TRACKBAR, TBM_SETPAGESIZE, (WPARAM)FALSE, (LPARAM)1);
- SendDlgItemMessage(hwndDlg, IDC_VOLUME_TRACKBAR, TBM_SETSEL, (WPARAM)FALSE, (LPARAM)MAKELONG(0, 10));
- SendDlgItemMessage(hwndDlg, IDC_VOLUME_TRACKBAR, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)4);
+ SendDlgItemMessage(hwndDlg, IDC_MUTE_CHECKBOX, BM_SETCHECK, (WPARAM)BST_UNCHECKED, (LPARAM)0);
+ SendDlgItemMessage(hwndDlg, IDC_MUTE_ICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)pGlobalData->hIconUnMuted);
}
+
+ GetVolumeControl(pGlobalData);
+ GetVolumeValue(pGlobalData);
+
+ SendDlgItemMessage(hwndDlg, IDC_DEVICE_NAME, WM_SETTEXT, 0, (LPARAM)mxc.szPname);
+ SendDlgItemMessage(hwndDlg, IDC_VOLUME_TRACKBAR, TBM_SETRANGE, (WPARAM)TRUE,
+ (LPARAM)MAKELONG(pGlobalData->volumeMinimum, pGlobalData->volumeMaximum/VOLUME_DIVIDER));
+ SendDlgItemMessage(hwndDlg, IDC_VOLUME_TRACKBAR, TBM_SETPAGESIZE, (WPARAM)FALSE, (LPARAM)1);
+ SendDlgItemMessage(hwndDlg, IDC_VOLUME_TRACKBAR, TBM_SETSEL, (WPARAM)FALSE,
+ (LPARAM)MAKELONG(pGlobalData->volumeMinimum, pGlobalData->volumeValue/VOLUME_DIVIDER));
+ SendDlgItemMessage(hwndDlg, IDC_VOLUME_TRACKBAR, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)pGlobalData->volumeValue/VOLUME_DIVIDER);
+}
+
+VOID
+LaunchSoundControl(HWND hwndDlg)
+{
+ if ((INT_PTR)ShellExecuteW(NULL, L"open", L"sndvol32.exe", NULL, NULL, SW_SHOWNORMAL) > 32)
+ return;
+ MessageBox(hwndDlg, _T("Cannot run sndvol32.exe"), NULL, MB_OK);
}
/* Volume property page dialog callback */
//static INT_PTR CALLBACK
INT_PTR CALLBACK
VolumeDlgProc(HWND hwndDlg,
- UINT uMsg,
- WPARAM wParam,
- LPARAM lParam)
+ UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam)
{
static IMGINFO ImgInfo;
+ PGLOBAL_DATA pGlobalData;
UNREFERENCED_PARAMETER(lParam);
UNREFERENCED_PARAMETER(wParam);
+ pGlobalData = (PGLOBAL_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
+
switch(uMsg)
{
case WM_INITDIALOG:
{
+ pGlobalData = (GLOBAL_DATA*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLOBAL_DATA));
+ SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pGlobalData);
+
+ pGlobalData->hIconUnMuted = LoadImage(hApplet, MAKEINTRESOURCE(IDI_CPLICON), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR);
+ pGlobalData->hIconMuted = LoadImage(hApplet, MAKEINTRESOURCE(IDI_MUTED_ICON), IMAGE_ICON, 32, 32, LR_DEFAULTCOLOR);
+
InitImageInfo(&ImgInfo);
- InitVolumeControls(hwndDlg);
+ InitVolumeControls(hwndDlg, pGlobalData);
break;
}
+
case WM_DRAWITEM:
{
LPDRAWITEMSTRUCT lpDrawItem;
DeleteDC(hdcMem);
}
}
- return TRUE;
+ break;
}
+
+ case WM_COMMAND:
+ {
+ switch (LOWORD(wParam))
+ {
+ case IDC_MUTE_CHECKBOX:
+ SwitchMuteState(pGlobalData);
+ if (pGlobalData->muteVal)
+ {
+ SendDlgItemMessage(hwndDlg, IDC_MUTE_CHECKBOX, BM_SETCHECK, (WPARAM)BST_CHECKED, (LPARAM)0);
+ SendDlgItemMessage(hwndDlg, IDC_MUTE_ICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)pGlobalData->hIconMuted);
+ }
+ else
+ {
+ SendDlgItemMessage(hwndDlg, IDC_MUTE_CHECKBOX, BM_SETCHECK, (WPARAM)BST_UNCHECKED, (LPARAM)0);
+ SendDlgItemMessage(hwndDlg, IDC_MUTE_ICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)pGlobalData->hIconUnMuted);
+ }
+ break;
+ case IDC_ADVANCED_BTN:
+ LaunchSoundControl(hwndDlg);
+ break;
+ }
+ break;
+ }
+
+ case WM_HSCROLL:
+ {
+ HWND hVolumeTrackbar = GetDlgItem(hwndDlg, IDC_VOLUME_TRACKBAR);
+ if (hVolumeTrackbar == (HWND)lParam)
+ {
+ pGlobalData->volumeValue = (DWORD)SendDlgItemMessage(hwndDlg, IDC_VOLUME_TRACKBAR, TBM_GETPOS, 0, 0)*VOLUME_DIVIDER;
+ SetVolumeValue(pGlobalData);
+ SendDlgItemMessage(hwndDlg, IDC_VOLUME_TRACKBAR, TBM_SETSEL, (WPARAM)TRUE,
+ (LPARAM)MAKELONG(pGlobalData->volumeMinimum, pGlobalData->volumeValue/VOLUME_DIVIDER));
+ }
+ break;
+ }
+
+ case WM_DESTROY:
+ mixerClose(pGlobalData->hMixer);
+ DestroyIcon(pGlobalData->hIconMuted);
+ DestroyIcon(pGlobalData->hIconUnMuted);
+ HeapFree(GetProcessHeap(), 0, pGlobalData);
+ break;
}
return FALSE;