2018-02-25 20:58:34 +00:00
|
|
|
/*
|
|
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
|
|
* PROJECT: ReactOS Sound Volume Control
|
|
|
|
* FILE: base/applications/sndvol32/tray.c
|
|
|
|
* PROGRAMMERS: Eric Kohl <eric.kohl@reactos.org>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "sndvol32.h"
|
|
|
|
|
2019-02-02 13:43:30 +00:00
|
|
|
typedef struct _DIALOG_DATA
|
|
|
|
{
|
|
|
|
HMIXER hMixer;
|
|
|
|
DWORD volumeControlID;
|
|
|
|
DWORD volumeChannels;
|
|
|
|
DWORD volumeMinimum;
|
|
|
|
DWORD volumeMaximum;
|
|
|
|
DWORD volumeStep;
|
|
|
|
|
|
|
|
DWORD maxVolume;
|
|
|
|
DWORD maxChannel;
|
|
|
|
PMIXERCONTROLDETAILS_UNSIGNED volumeInitValues;
|
|
|
|
PMIXERCONTROLDETAILS_UNSIGNED volumeCurrentValues;
|
2019-02-02 16:21:35 +00:00
|
|
|
|
|
|
|
DWORD muteControlID;
|
2019-02-02 13:43:30 +00:00
|
|
|
} DIALOG_DATA, *PDIALOG_DATA;
|
|
|
|
|
|
|
|
|
2018-02-25 20:58:34 +00:00
|
|
|
static VOID
|
|
|
|
OnTrayInitDialog(
|
|
|
|
HWND hwnd,
|
|
|
|
WPARAM wParam,
|
|
|
|
LPARAM lParam)
|
|
|
|
{
|
|
|
|
POINT ptCursor;
|
|
|
|
RECT rcWindow;
|
|
|
|
RECT rcScreen;
|
|
|
|
LONG x, y, cx, cy;
|
|
|
|
|
|
|
|
GetCursorPos(&ptCursor);
|
|
|
|
|
|
|
|
GetWindowRect(hwnd, &rcWindow);
|
|
|
|
|
|
|
|
GetWindowRect(GetDesktopWindow(), &rcScreen);
|
|
|
|
|
|
|
|
cx = rcWindow.right - rcWindow.left;
|
|
|
|
cy = rcWindow.bottom - rcWindow.top;
|
|
|
|
|
|
|
|
if (ptCursor.y + cy > rcScreen.bottom)
|
|
|
|
y = ptCursor.y - cy;
|
|
|
|
else
|
|
|
|
y = ptCursor.y;
|
|
|
|
|
|
|
|
if (ptCursor.x + cx > rcScreen.right)
|
|
|
|
x = ptCursor.x - cx;
|
|
|
|
else
|
|
|
|
x = ptCursor.x;
|
|
|
|
|
|
|
|
SetWindowPos(hwnd, HWND_TOPMOST, x, y, 0, 0, SWP_NOSIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-02-02 13:43:30 +00:00
|
|
|
static
|
|
|
|
VOID
|
|
|
|
OnTrayInitMixer(
|
|
|
|
PDIALOG_DATA pDialogData,
|
|
|
|
HWND hwndDlg)
|
|
|
|
{
|
|
|
|
MIXERLINE mxln;
|
|
|
|
MIXERCONTROL mxc;
|
|
|
|
MIXERLINECONTROLS mxlctrl;
|
|
|
|
MIXERCONTROLDETAILS mxcd;
|
2019-02-02 16:21:35 +00:00
|
|
|
MIXERCONTROLDETAILS_BOOLEAN mxcdBool;
|
2019-02-02 13:43:30 +00:00
|
|
|
DWORD i;
|
|
|
|
|
|
|
|
/* Open the mixer */
|
|
|
|
if (mixerOpen(&pDialogData->hMixer, 0, PtrToUlong(hwndDlg), 0, MIXER_OBJECTF_MIXER | CALLBACK_WINDOW) != MMSYSERR_NOERROR)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Retrieve the mixer information */
|
|
|
|
mxln.cbStruct = sizeof(MIXERLINE);
|
|
|
|
mxln.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
|
|
|
|
|
|
|
|
if (mixerGetLineInfo((HMIXEROBJ)pDialogData->hMixer, &mxln, MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_COMPONENTTYPE) != MMSYSERR_NOERROR)
|
|
|
|
return;
|
|
|
|
|
|
|
|
pDialogData->volumeChannels = mxln.cChannels;
|
|
|
|
|
|
|
|
/* Retrieve the line information */
|
|
|
|
mxlctrl.cbStruct = sizeof(MIXERLINECONTROLS);
|
|
|
|
mxlctrl.dwLineID = mxln.dwLineID;
|
|
|
|
mxlctrl.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
|
|
|
|
mxlctrl.cControls = 1;
|
|
|
|
mxlctrl.cbmxctrl = sizeof(MIXERCONTROL);
|
|
|
|
mxlctrl.pamxctrl = &mxc;
|
|
|
|
|
|
|
|
if (mixerGetLineControls((HMIXEROBJ)pDialogData->hMixer, &mxlctrl, MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE) != MMSYSERR_NOERROR)
|
|
|
|
return;
|
|
|
|
|
|
|
|
pDialogData->volumeControlID = mxc.dwControlID;
|
|
|
|
pDialogData->volumeMinimum = mxc.Bounds.dwMinimum;
|
|
|
|
pDialogData->volumeMaximum = mxc.Bounds.dwMaximum;
|
|
|
|
pDialogData->volumeStep = (pDialogData->volumeMaximum - pDialogData->volumeMinimum) / (VOLUME_MAX - VOLUME_MIN);
|
|
|
|
|
|
|
|
/* Allocate a buffer for all channel volume values */
|
|
|
|
pDialogData->volumeInitValues = HeapAlloc(GetProcessHeap(),
|
|
|
|
0,
|
|
|
|
mxln.cChannels * sizeof(MIXERCONTROLDETAILS_UNSIGNED));
|
|
|
|
if (pDialogData->volumeInitValues == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
pDialogData->volumeCurrentValues = HeapAlloc(GetProcessHeap(),
|
|
|
|
0,
|
|
|
|
mxln.cChannels * sizeof(MIXERCONTROLDETAILS_UNSIGNED));
|
|
|
|
if (pDialogData->volumeCurrentValues == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Retrieve the channel volume values */
|
|
|
|
mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
|
|
|
|
mxcd.dwControlID = mxc.dwControlID;
|
|
|
|
mxcd.cChannels = mxln.cChannels;
|
|
|
|
mxcd.cMultipleItems = 0;
|
|
|
|
mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
|
|
|
|
mxcd.paDetails = pDialogData->volumeInitValues;
|
|
|
|
|
|
|
|
if (mixerGetControlDetails((HMIXEROBJ)pDialogData->hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_GETCONTROLDETAILSF_VALUE) != MMSYSERR_NOERROR)
|
|
|
|
return;
|
|
|
|
|
2019-02-05 19:33:43 +00:00
|
|
|
pDialogData->maxVolume = 0;
|
|
|
|
for (i = 0; i < pDialogData->volumeChannels; i++)
|
2019-02-02 13:43:30 +00:00
|
|
|
{
|
2019-02-05 19:33:43 +00:00
|
|
|
pDialogData->volumeCurrentValues[i].dwValue = pDialogData->volumeInitValues[i].dwValue;
|
|
|
|
|
2019-02-02 13:43:30 +00:00
|
|
|
if (pDialogData->volumeInitValues[i].dwValue > pDialogData->maxVolume)
|
|
|
|
pDialogData->maxVolume = pDialogData->volumeInitValues[i].dwValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initialize the volume trackbar */
|
|
|
|
SendDlgItemMessage(hwndDlg, IDC_LINE_SLIDER_VERT, TBM_SETRANGE, TRUE, MAKELONG(VOLUME_MIN, VOLUME_MAX));
|
|
|
|
SendDlgItemMessage(hwndDlg, IDC_LINE_SLIDER_VERT, TBM_SETPAGESIZE, 0, VOLUME_PAGE_SIZE);
|
|
|
|
SendDlgItemMessage(hwndDlg, IDC_LINE_SLIDER_VERT, TBM_SETPOS, TRUE, VOLUME_MAX -(pDialogData->maxVolume - pDialogData->volumeMinimum) / pDialogData->volumeStep);
|
2019-02-02 16:21:35 +00:00
|
|
|
|
|
|
|
/* Retrieve the mute control information */
|
|
|
|
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)pDialogData->hMixer, &mxlctrl, MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE) != MMSYSERR_NOERROR)
|
|
|
|
return;
|
|
|
|
|
|
|
|
pDialogData->muteControlID = mxc.dwControlID;
|
|
|
|
|
|
|
|
/* Retrieve the mute value */
|
|
|
|
mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
|
|
|
|
mxcd.dwControlID = mxc.dwControlID;
|
|
|
|
mxcd.cChannels = 1;
|
|
|
|
mxcd.cMultipleItems = 0;
|
|
|
|
mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
|
|
|
|
mxcd.paDetails = &mxcdBool;
|
|
|
|
|
|
|
|
if (mixerGetControlDetails((HMIXEROBJ)pDialogData->hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_GETCONTROLDETAILSF_VALUE) != MMSYSERR_NOERROR)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Initialize the mute checkbox */
|
|
|
|
SendDlgItemMessage(hwndDlg, IDC_LINE_SWITCH, BM_SETCHECK, (WPARAM)(mxcdBool.fValue ? BST_CHECKED : BST_UNCHECKED), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static
|
|
|
|
VOID
|
|
|
|
OnCommand(
|
|
|
|
PDIALOG_DATA pDialogData,
|
|
|
|
HWND hwndDlg,
|
|
|
|
WPARAM wParam,
|
|
|
|
LPARAM lParam)
|
|
|
|
{
|
|
|
|
MIXERCONTROLDETAILS mxcd;
|
|
|
|
MIXERCONTROLDETAILS_BOOLEAN mxcdMute;
|
|
|
|
|
|
|
|
if ((LOWORD(wParam) == IDC_LINE_SWITCH) &&
|
|
|
|
(HIWORD(wParam) == BN_CLICKED))
|
|
|
|
{
|
|
|
|
mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
|
|
|
|
mxcd.dwControlID = pDialogData->muteControlID;
|
|
|
|
mxcd.cChannels = 1;
|
|
|
|
mxcd.cMultipleItems = 0;
|
|
|
|
mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
|
|
|
|
mxcd.paDetails = &mxcdMute;
|
|
|
|
|
|
|
|
mxcdMute.fValue = (SendMessage((HWND)lParam, BM_GETCHECK, 0, 0) == BST_CHECKED);
|
|
|
|
|
|
|
|
mixerSetControlDetails((HMIXEROBJ)pDialogData->hMixer,
|
|
|
|
&mxcd,
|
|
|
|
MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE);
|
|
|
|
}
|
2019-02-02 13:43:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static
|
|
|
|
VOID
|
|
|
|
OnVScroll(
|
|
|
|
PDIALOG_DATA pDialogData,
|
|
|
|
HWND hwndDlg,
|
|
|
|
WPARAM wParam,
|
|
|
|
LPARAM lParam)
|
|
|
|
{
|
|
|
|
MIXERCONTROLDETAILS mxcd;
|
2019-02-05 19:33:43 +00:00
|
|
|
DWORD dwPosition, dwVolume, i;
|
2019-02-02 13:43:30 +00:00
|
|
|
|
|
|
|
switch (LOWORD(wParam))
|
|
|
|
{
|
2019-02-05 19:33:43 +00:00
|
|
|
case TB_THUMBPOSITION:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TB_ENDTRACK:
|
|
|
|
PlaySound((LPCTSTR)SND_ALIAS_SYSTEMDEFAULT, NULL, SND_ASYNC | SND_ALIAS_ID);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
dwPosition = VOLUME_MAX - (DWORD)SendDlgItemMessage(hwndDlg, IDC_LINE_SLIDER_VERT, TBM_GETPOS, 0, 0);
|
2019-02-02 13:43:30 +00:00
|
|
|
|
2019-02-05 19:33:43 +00:00
|
|
|
if (dwPosition == VOLUME_MIN)
|
|
|
|
dwVolume = pDialogData->volumeMinimum;
|
|
|
|
else if (dwPosition == VOLUME_MAX)
|
|
|
|
dwVolume = pDialogData->volumeMaximum;
|
|
|
|
else
|
|
|
|
dwVolume = (dwPosition * pDialogData->volumeStep) + pDialogData->volumeMinimum;
|
2019-02-02 13:43:30 +00:00
|
|
|
|
|
|
|
for (i = 0; i < pDialogData->volumeChannels; i++)
|
|
|
|
{
|
2019-02-05 19:33:43 +00:00
|
|
|
if (pDialogData->volumeInitValues[i].dwValue == pDialogData->maxVolume)
|
2019-02-02 13:43:30 +00:00
|
|
|
{
|
|
|
|
pDialogData->volumeCurrentValues[i].dwValue = dwVolume;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pDialogData->volumeCurrentValues[i].dwValue =
|
|
|
|
pDialogData->volumeInitValues[i].dwValue * dwVolume / pDialogData-> maxVolume;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
|
|
|
|
mxcd.dwControlID = pDialogData->volumeControlID;
|
|
|
|
mxcd.cChannels = pDialogData->volumeChannels;
|
|
|
|
mxcd.cMultipleItems = 0;
|
|
|
|
mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
|
|
|
|
mxcd.paDetails = pDialogData->volumeCurrentValues;
|
|
|
|
|
|
|
|
mixerSetControlDetails((HMIXEROBJ)pDialogData->hMixer,
|
|
|
|
&mxcd,
|
|
|
|
MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-02-25 20:58:34 +00:00
|
|
|
INT_PTR
|
|
|
|
CALLBACK
|
|
|
|
TrayDlgProc(
|
|
|
|
HWND hwndDlg,
|
|
|
|
UINT uMsg,
|
|
|
|
WPARAM wParam,
|
|
|
|
LPARAM lParam)
|
|
|
|
{
|
2019-02-02 13:43:30 +00:00
|
|
|
PDIALOG_DATA pDialogData;
|
|
|
|
|
|
|
|
pDialogData = (PDIALOG_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
|
|
|
|
|
2018-02-25 20:58:34 +00:00
|
|
|
switch (uMsg)
|
|
|
|
{
|
|
|
|
case WM_INITDIALOG:
|
|
|
|
OnTrayInitDialog(hwndDlg, wParam, lParam);
|
2019-02-02 13:43:30 +00:00
|
|
|
|
|
|
|
pDialogData = (PDIALOG_DATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DIALOG_DATA));
|
|
|
|
SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pDialogData);
|
|
|
|
|
|
|
|
if (pDialogData)
|
|
|
|
OnTrayInitMixer(pDialogData, hwndDlg);
|
|
|
|
break;
|
|
|
|
|
2019-02-02 16:21:35 +00:00
|
|
|
case WM_COMMAND:
|
|
|
|
if (pDialogData)
|
|
|
|
OnCommand(pDialogData, hwndDlg, wParam, lParam);
|
|
|
|
break;
|
|
|
|
|
2019-02-02 13:43:30 +00:00
|
|
|
case WM_VSCROLL:
|
|
|
|
if (pDialogData)
|
|
|
|
OnVScroll(pDialogData, hwndDlg, wParam, lParam);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WM_DESTROY:
|
|
|
|
if (pDialogData)
|
|
|
|
{
|
|
|
|
if (pDialogData->volumeInitValues)
|
|
|
|
HeapFree(GetProcessHeap(), 0, pDialogData->volumeInitValues);
|
|
|
|
|
|
|
|
if (pDialogData->volumeCurrentValues)
|
|
|
|
HeapFree(GetProcessHeap(), 0, pDialogData->volumeCurrentValues);
|
|
|
|
|
|
|
|
if (pDialogData->hMixer)
|
|
|
|
mixerClose(pDialogData->hMixer);
|
|
|
|
|
|
|
|
HeapFree(GetProcessHeap(), 0, pDialogData);
|
|
|
|
pDialogData = NULL;
|
|
|
|
SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)NULL);
|
|
|
|
}
|
2018-02-25 20:58:34 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case WM_ACTIVATE:
|
|
|
|
if (LOWORD(wParam) == WA_INACTIVE)
|
|
|
|
EndDialog(hwndDlg, IDOK);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* EOF */
|