/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS Sound Volume Control * FILE: base/applications/sndvol32/tray.c * PROGRAMMERS: Eric Kohl */ #include "sndvol32.h" 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; DWORD muteControlID; } DIALOG_DATA, *PDIALOG_DATA; 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); } static VOID OnTrayInitMixer( PDIALOG_DATA pDialogData, HWND hwndDlg) { MIXERLINE mxln; MIXERCONTROL mxc; MIXERLINECONTROLS mxlctrl; MIXERCONTROLDETAILS mxcd; MIXERCONTROLDETAILS_BOOLEAN mxcdBool; 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; pDialogData->maxVolume = 0; for (i = 0; i < pDialogData->volumeChannels; i++) { pDialogData->volumeCurrentValues[i].dwValue = pDialogData->volumeInitValues[i].dwValue; 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); /* 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); } } static VOID OnVScroll( PDIALOG_DATA pDialogData, HWND hwndDlg, WPARAM wParam, LPARAM lParam) { MIXERCONTROLDETAILS mxcd; DWORD dwPosition, dwVolume, i; switch (LOWORD(wParam)) { 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); if (dwPosition == VOLUME_MIN) dwVolume = pDialogData->volumeMinimum; else if (dwPosition == VOLUME_MAX) dwVolume = pDialogData->volumeMaximum; else dwVolume = (dwPosition * pDialogData->volumeStep) + pDialogData->volumeMinimum; for (i = 0; i < pDialogData->volumeChannels; i++) { if (pDialogData->volumeInitValues[i].dwValue == pDialogData->maxVolume) { 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; } } INT_PTR CALLBACK TrayDlgProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { PDIALOG_DATA pDialogData; pDialogData = (PDIALOG_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER); switch (uMsg) { case WM_INITDIALOG: OnTrayInitDialog(hwndDlg, wParam, lParam); pDialogData = (PDIALOG_DATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DIALOG_DATA)); SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pDialogData); if (pDialogData) OnTrayInitMixer(pDialogData, hwndDlg); break; case WM_COMMAND: if (pDialogData) OnCommand(pDialogData, hwndDlg, wParam, lParam); break; 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); } break; case WM_ACTIVATE: if (LOWORD(wParam) == WA_INACTIVE) EndDialog(hwndDlg, IDOK); break; } return 0; } /* EOF */