ReactOS 0.4.16-dev-2206-gc56950d
tray.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Sound Volume Control
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Tray pop-up for adjusting master volume and muting
5 * COPYRIGHT: Copyright 2018-2019 Eric Kohl <eric.kohl@reactos.org>
6 * Copyright 2026 Vitaly Orekhov <vkvo2000@vivaldi.net>
7 */
8
9#include "sndvol32.h"
10
11typedef struct _DIALOG_DATA
12{
13 HMIXER hMixer;
19
24
27
28
29static VOID
31 HWND hwnd,
34{
35 POINT ptCursor;
36 RECT rcWindow;
37 RECT rcScreen;
38 LONG x, y, cx, cy;
39
40 GetCursorPos(&ptCursor);
41
42 GetWindowRect(hwnd, &rcWindow);
43
44 GetWindowRect(GetDesktopWindow(), &rcScreen);
45
46 cx = rcWindow.right - rcWindow.left;
47 cy = rcWindow.bottom - rcWindow.top;
48
49 if (ptCursor.y + cy > rcScreen.bottom)
50 y = ptCursor.y - cy;
51 else
52 y = ptCursor.y;
53
54 if (ptCursor.x + cx > rcScreen.right)
55 x = ptCursor.x - cx;
56 else
57 x = ptCursor.x;
58
60}
61
62
63static
64VOID
66 PDIALOG_DATA pDialogData,
67 HWND hwndDlg)
68{
69 MIXERLINE mxln;
70 MIXERCONTROL mxc;
71 MIXERLINECONTROLS mxlctrl;
74 DWORD i;
75
76 /* Open the mixer */
77 if (mixerOpen(&pDialogData->hMixer, 0, PtrToUlong(hwndDlg), 0, MIXER_OBJECTF_MIXER | CALLBACK_WINDOW) != MMSYSERR_NOERROR)
78 return;
79
80 /* Retrieve the mixer information */
81 mxln.cbStruct = sizeof(MIXERLINE);
83
85 return;
86
87 pDialogData->volumeChannels = mxln.cChannels;
88
89 /* Retrieve the line information */
90 mxlctrl.cbStruct = sizeof(MIXERLINECONTROLS);
91 mxlctrl.dwLineID = mxln.dwLineID;
93 mxlctrl.cControls = 1;
94 mxlctrl.cbmxctrl = sizeof(MIXERCONTROL);
95 mxlctrl.pamxctrl = &mxc;
96
98 return;
99
100 pDialogData->volumeControlID = mxc.dwControlID;
101 pDialogData->volumeMinimum = mxc.Bounds.dwMinimum;
102 pDialogData->volumeMaximum = mxc.Bounds.dwMaximum;
103 pDialogData->volumeStep = (pDialogData->volumeMaximum - pDialogData->volumeMinimum) / (VOLUME_MAX - VOLUME_MIN);
104
105 /* Allocate a buffer for all channel volume values */
107 0,
109 if (pDialogData->volumeInitValues == NULL)
110 return;
111
113 0,
115 if (pDialogData->volumeCurrentValues == NULL)
116 return;
117
118 /* Retrieve the channel volume values */
119 mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
120 mxcd.dwControlID = mxc.dwControlID;
121 mxcd.cChannels = mxln.cChannels;
122 mxcd.cMultipleItems = 0;
124 mxcd.paDetails = pDialogData->volumeInitValues;
125
127 return;
128
129 pDialogData->maxVolume = 0;
130 for (i = 0; i < pDialogData->volumeChannels; i++)
131 {
132 pDialogData->volumeCurrentValues[i].dwValue = pDialogData->volumeInitValues[i].dwValue;
133
134 if (pDialogData->volumeInitValues[i].dwValue > pDialogData->maxVolume)
135 pDialogData->maxVolume = pDialogData->volumeInitValues[i].dwValue;
136 }
137
138 /* Initialize the volume trackbar */
141 SendDlgItemMessage(hwndDlg, IDC_LINE_SLIDER_VERT, TBM_SETPOS, TRUE, VOLUME_MAX -(pDialogData->maxVolume - pDialogData->volumeMinimum) / pDialogData->volumeStep);
142
143 /* Retrieve the mute control information */
144 mxlctrl.cbStruct = sizeof(MIXERLINECONTROLS);
145 mxlctrl.dwLineID = mxln.dwLineID;
147 mxlctrl.cControls = 1;
148 mxlctrl.cbmxctrl = sizeof(MIXERCONTROL);
149 mxlctrl.pamxctrl = &mxc;
150
152 return;
153
154 pDialogData->muteControlID = mxc.dwControlID;
155
156 /* Retrieve the mute value */
157 mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
158 mxcd.dwControlID = mxc.dwControlID;
159 mxcd.cChannels = 1;
160 mxcd.cMultipleItems = 0;
162 mxcd.paDetails = &mxcdBool;
163
165 return;
166
167 /* Initialize the mute checkbox */
169}
170
171
172static
173VOID
175 PDIALOG_DATA pDialogData,
176 HWND hwndDlg,
179{
182
183 if ((LOWORD(wParam) == IDC_LINE_SWITCH) &&
185 {
186 mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
187 mxcd.dwControlID = pDialogData->muteControlID;
188 mxcd.cChannels = 1;
189 mxcd.cMultipleItems = 0;
191 mxcd.paDetails = &mxcdMute;
192
193 mxcdMute.fValue = (SendMessage((HWND)lParam, BM_GETCHECK, 0, 0) == BST_CHECKED);
194
195 mixerSetControlDetails((HMIXEROBJ)pDialogData->hMixer,
196 &mxcd,
198 }
199}
200
201
202static
203VOID
205 PDIALOG_DATA pDialogData,
206 HWND hwndDlg,
209{
211 DWORD dwPosition, dwVolume, i;
212
213 switch (LOWORD(wParam))
214 {
215 case TB_THUMBPOSITION:
216 break;
217
218 case TB_ENDTRACK:
220 break;
221
222 default:
223 dwPosition = VOLUME_MAX - (DWORD)SendDlgItemMessage(hwndDlg, IDC_LINE_SLIDER_VERT, TBM_GETPOS, 0, 0);
224
225 if (dwPosition == VOLUME_MIN)
226 dwVolume = pDialogData->volumeMinimum;
227 else if (dwPosition == VOLUME_MAX)
228 dwVolume = pDialogData->volumeMaximum;
229 else
230 dwVolume = (dwPosition * pDialogData->volumeStep) + pDialogData->volumeMinimum;
231
232 for (i = 0; i < pDialogData->volumeChannels; i++)
233 {
234 if (pDialogData->volumeInitValues[i].dwValue == pDialogData->maxVolume)
235 {
236 pDialogData->volumeCurrentValues[i].dwValue = dwVolume;
237 }
238 else
239 {
240 pDialogData->volumeCurrentValues[i].dwValue =
241 pDialogData->volumeInitValues[i].dwValue * dwVolume / pDialogData-> maxVolume;
242 }
243 }
244
245 mxcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
246 mxcd.dwControlID = pDialogData->volumeControlID;
247 mxcd.cChannels = pDialogData->volumeChannels;
248 mxcd.cMultipleItems = 0;
250 mxcd.paDetails = pDialogData->volumeCurrentValues;
251
252 mixerSetControlDetails((HMIXEROBJ)pDialogData->hMixer,
253 &mxcd,
255 break;
256 }
257}
258
259static
260VOID
262 PDIALOG_DATA pDialogData,
263 HWND hwndDlg,
266{
267 HMIXER hMixer = (HMIXER)wParam;
268 DWORD dwControlID = lParam;
269
270 if (hMixer != pDialogData->hMixer)
271 return;
272
274 mxcd.cbStruct = sizeof(mxcd);
275 mxcd.dwControlID = dwControlID;
276 mxcd.cMultipleItems = 0;
277
278 if (dwControlID == pDialogData->muteControlID)
279 {
281
282 mxcd.cChannels = 1;
283 mxcd.cbDetails = sizeof(mxcdBool);
284 mxcd.paDetails = &mxcdBool;
285
288 }
289 else if (dwControlID == pDialogData->volumeControlID)
290 {
292
293 mxcdVolume = HeapAlloc(GetProcessHeap(), 0, pDialogData->volumeChannels * sizeof(*mxcdVolume));
294 if (mxcdVolume == NULL)
295 return;
296
297 mxcd.cChannels = pDialogData->volumeChannels;
298 mxcd.cbDetails = sizeof(*mxcdVolume);
299 mxcd.paDetails = mxcdVolume;
300
302 return;
303
304 /* The Volume trackbar always shows the maximum volume value of all channels.
305 * Changing volume balance in "full" sndvol32 view must not affect it. */
306 DWORD dwVolume = 0;
307 for (int i = 0; i < pDialogData->volumeChannels; ++i)
308 {
309 if (mxcdVolume[i].dwValue <= dwVolume)
310 continue;
311
312 dwVolume = mxcdVolume[i].dwValue;
313 }
314
315 DWORD dwNewPosition = VOLUME_MAX - dwVolume / pDialogData->volumeStep;
316 SendDlgItemMessageW(hwndDlg, IDC_LINE_SLIDER_VERT, TBM_SETPOS, TRUE, dwNewPosition);
317
318 HeapFree(GetProcessHeap(), 0, mxcdVolume);
319 }
320}
321
325 HWND hwndDlg,
326 UINT uMsg,
329{
330 PDIALOG_DATA pDialogData;
331
332 pDialogData = (PDIALOG_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
333
334 switch (uMsg)
335 {
336 case WM_INITDIALOG:
337 OnTrayInitDialog(hwndDlg, wParam, lParam);
338
340 SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pDialogData);
341
342 if (pDialogData)
343 OnTrayInitMixer(pDialogData, hwndDlg);
344 break;
345
346 case WM_COMMAND:
347 if (pDialogData)
348 OnCommand(pDialogData, hwndDlg, wParam, lParam);
349 break;
350
351 case WM_VSCROLL:
352 if (pDialogData)
353 OnVScroll(pDialogData, hwndDlg, wParam, lParam);
354 break;
355
356 case WM_DESTROY:
357 if (pDialogData)
358 {
359 if (pDialogData->volumeInitValues)
360 HeapFree(GetProcessHeap(), 0, pDialogData->volumeInitValues);
361
362 if (pDialogData->volumeCurrentValues)
363 HeapFree(GetProcessHeap(), 0, pDialogData->volumeCurrentValues);
364
365 if (pDialogData->hMixer)
366 mixerClose(pDialogData->hMixer);
367
368 HeapFree(GetProcessHeap(), 0, pDialogData);
369 pDialogData = NULL;
371 }
372 break;
373
374 case WM_ACTIVATE:
375 if (LOWORD(wParam) == WA_INACTIVE)
376 EndDialog(hwndDlg, IDOK);
377 break;
378
380 if (pDialogData)
381 OnMixerControlChange(pDialogData, hwndDlg, wParam, lParam);
382 break;
383 }
384
385 return 0;
386}
387
388/* EOF */
#define IDC_LINE_SLIDER_VERT
Definition: resources.h:25
#define IDC_LINE_SWITCH
Definition: resources.h:23
WPARAM wParam
Definition: combotst.c:138
LPARAM lParam
Definition: combotst.c:139
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define GetProcessHeap()
Definition: compat.h:736
#define HeapAlloc
Definition: compat.h:733
#define HeapFree(x, y, z)
Definition: compat.h:735
#define CALLBACK
Definition: compat.h:35
#define HEAP_ZERO_MEMORY
Definition: compat.h:134
#define PtrToUlong(u)
Definition: config.h:107
unsigned long DWORD
Definition: ntddk_ex.h:95
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
GLint GLint GLint GLint GLint GLint y
Definition: gl.h:1548
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
LONG_PTR LPARAM
Definition: minwindef.h:175
UINT_PTR WPARAM
Definition: minwindef.h:174
#define CALLBACK_WINDOW
Definition: mmsystem.h:148
#define MIXERLINE_COMPONENTTYPE_DST_SPEAKERS
Definition: mmsystem.h:319
#define MIXER_OBJECTF_MIXER
Definition: mmsystem.h:300
MIXERCONTROLA MIXERCONTROL
Definition: mmsystem.h:2825
#define PlaySound
Definition: mmsystem.h:2842
MIXERLINECONTROLSA MIXERLINECONTROLS
Definition: mmsystem.h:2826
#define MIXER_SETCONTROLDETAILSF_VALUE
Definition: mmsystem.h:415
#define MIXER_GETCONTROLDETAILSF_VALUE
Definition: mmsystem.h:412
#define SND_ALIAS_SYSTEMDEFAULT
Definition: mmsystem.h:175
#define MM_MIXM_CONTROL_CHANGE
Definition: mmsystem.h:83
#define mixerGetControlDetails
Definition: mmsystem.h:2855
#define mixerGetLineControls
Definition: mmsystem.h:2854
#define MIXERCONTROL_CONTROLTYPE_VOLUME
Definition: mmsystem.h:398
MIXERLINEA MIXERLINE
Definition: mmsystem.h:2824
#define MIXER_GETLINEINFOF_COMPONENTTYPE
Definition: mmsystem.h:347
#define SND_ALIAS_ID
Definition: mmsystem.h:161
#define MMSYSERR_NOERROR
Definition: mmsystem.h:96
#define mixerGetLineInfo
Definition: mmsystem.h:2853
struct tMIXERCONTROLDETAILS_BOOLEAN MIXERCONTROLDETAILS_BOOLEAN
#define SND_ASYNC
Definition: mmsystem.h:154
struct tMIXERCONTROLDETAILS MIXERCONTROLDETAILS
struct tMIXERCONTROLDETAILS_UNSIGNED MIXERCONTROLDETAILS_UNSIGNED
#define MIXER_GETLINECONTROLSF_ONEBYTYPE
Definition: mmsystem.h:410
#define MIXER_OBJECTF_HMIXER
Definition: mmsystem.h:301
#define MIXERCONTROL_CONTROLTYPE_MUTE
Definition: mmsystem.h:384
#define for
Definition: utility.h:88
HMIXER hMixer
Definition: test.c:10
__int3264 LONG_PTR
Definition: mstsclib_h.h:276
unsigned int UINT
Definition: ndis.h:50
#define DWORD
Definition: nt_native.h:44
#define LOWORD(l)
Definition: pedump.c:82
long LONG
Definition: pedump.c:60
_Out_opt_ int _Out_opt_ int * cy
Definition: commctrl.h:586
#define TB_ENDTRACK
Definition: commctrl.h:2086
#define TBM_SETPAGESIZE
Definition: commctrl.h:2056
#define TB_THUMBPOSITION
Definition: commctrl.h:2082
#define TBM_GETPOS
Definition: commctrl.h:2036
_Out_opt_ int * cx
Definition: commctrl.h:585
#define TBM_SETRANGE
Definition: commctrl.h:2042
#define TBM_SETPOS
Definition: commctrl.h:2041
#define VOLUME_MAX
Definition: sndvol32.h:19
#define VOLUME_PAGE_SIZE
Definition: sndvol32.h:21
#define VOLUME_MIN
Definition: sndvol32.h:18
DWORD volumeChannels
Definition: tray.c:15
DWORD volumeStep
Definition: tray.c:18
DWORD volumeControlID
Definition: tray.c:14
PMIXERCONTROLDETAILS_UNSIGNED volumeCurrentValues
Definition: tray.c:23
PMIXERCONTROLDETAILS_UNSIGNED volumeInitValues
Definition: tray.c:22
DWORD maxChannel
Definition: tray.c:21
DWORD volumeMaximum
Definition: tray.c:17
DWORD maxVolume
Definition: tray.c:20
DWORD muteControlID
Definition: tray.c:25
HMIXER hMixer
Definition: tray.c:13
DWORD volumeMinimum
Definition: tray.c:16
union tagMIXERCONTROLA::@3262 Bounds
DWORD dwComponentType
Definition: mmsystem.h:1238
DWORD dwLineID
Definition: mmsystem.h:1235
DWORD cbStruct
Definition: mmsystem.h:1232
DWORD cChannels
Definition: mmsystem.h:1239
LPMIXERCONTROLA pamxctrl
Definition: mmsystem.h:1338
long y
Definition: polytest.cpp:48
long x
Definition: polytest.cpp:48
LONG right
Definition: windef.h:108
LONG bottom
Definition: windef.h:109
LONG top
Definition: windef.h:107
LONG left
Definition: windef.h:106
static VOID OnMixerControlChange(PDIALOG_DATA pDialogData, HWND hwndDlg, WPARAM wParam, LPARAM lParam)
Definition: tray.c:261
static VOID OnCommand(PDIALOG_DATA pDialogData, HWND hwndDlg, WPARAM wParam, LPARAM lParam)
Definition: tray.c:174
static VOID OnTrayInitMixer(PDIALOG_DATA pDialogData, HWND hwndDlg)
Definition: tray.c:65
struct _DIALOG_DATA DIALOG_DATA
static VOID OnTrayInitDialog(HWND hwnd, WPARAM wParam, LPARAM lParam)
Definition: tray.c:30
struct _DIALOG_DATA * PDIALOG_DATA
static VOID OnVScroll(PDIALOG_DATA pDialogData, HWND hwndDlg, WPARAM wParam, LPARAM lParam)
Definition: tray.c:204
INT_PTR CALLBACK TrayDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
Definition: tray.c:324
#define GetWindowLongPtr
Definition: treelist.c:73
#define SetWindowLongPtr
Definition: treelist.c:70
int32_t INT_PTR
Definition: typedefs.h:64
#define MAKELONG(a, b)
Definition: typedefs.h:249
#define HIWORD(l)
Definition: typedefs.h:247
_In_ LONG _In_ HWND hwnd
Definition: winddi.h:4023
UINT WINAPI mixerClose(HMIXER hMix)
Definition: winmm.c:386
UINT WINAPI mixerOpen(LPHMIXER lphMix, UINT uDeviceID, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen)
Definition: winmm.c:339
UINT WINAPI mixerSetControlDetails(HMIXEROBJ hmix, LPMIXERCONTROLDETAILS lpmcd, DWORD fdwDetails)
Definition: winmm.c:681
#define DWLP_USER
Definition: winuser.h:883
#define HWND_TOPMOST
Definition: winuser.h:1219
#define BST_UNCHECKED
Definition: winuser.h:199
#define WM_VSCROLL
Definition: winuser.h:1772
BOOL WINAPI GetWindowRect(_In_ HWND, _Out_ LPRECT)
BOOL WINAPI SetWindowPos(_In_ HWND, _In_opt_ HWND, _In_ int, _In_ int, _In_ int, _In_ int, _In_ UINT)
#define WM_COMMAND
Definition: winuser.h:1768
BOOL WINAPI GetCursorPos(_Out_ LPPOINT)
Definition: cursoricon.c:3047
#define SWP_NOSIZE
Definition: winuser.h:1256
#define WA_INACTIVE
Definition: winuser.h:2664
#define WM_INITDIALOG
Definition: winuser.h:1767
#define IDOK
Definition: winuser.h:841
#define BM_SETCHECK
Definition: winuser.h:1950
#define WM_ACTIVATE
Definition: winuser.h:1640
LRESULT WINAPI SendDlgItemMessageW(_In_ HWND, _In_ int, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
HWND WINAPI GetDesktopWindow(void)
Definition: window.c:628
#define SendMessage
Definition: winuser.h:5954
#define BN_CLICKED
Definition: winuser.h:1954
#define WM_DESTROY
Definition: winuser.h:1637
#define SendDlgItemMessage
Definition: winuser.h:5953
#define BST_CHECKED
Definition: winuser.h:197
#define BM_GETCHECK
Definition: winuser.h:1947
BOOL WINAPI EndDialog(_In_ HWND, _In_ INT_PTR)
const CHAR * LPCTSTR
Definition: xmlstorage.h:193