xref: /reactos/base/applications/sndvol32/dialog.c (revision fe5c50e1)
1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS Sound Volume Control
4  * FILE:        base/applications/sndvol32/dialog.c
5  * PROGRAMMERS: Johannes Anderwald
6  */
7 
8 #include "sndvol32.h"
9 
10 
11 VOID
12 ConvertRect(LPRECT lpRect, UINT xBaseUnit, UINT yBaseUnit)
13 {
14     lpRect->left = MulDiv(lpRect->left, xBaseUnit, 4);
15     lpRect->right = MulDiv(lpRect->right, xBaseUnit, 4);
16     lpRect->top = MulDiv(lpRect->top, yBaseUnit, 8);
17     lpRect->bottom = MulDiv(lpRect->bottom, yBaseUnit, 8);
18 }
19 
20 LPVOID
21 LoadDialogResource(
22     IN HMODULE hModule,
23     IN LPCWSTR ResourceName,
24     OUT LPDWORD ResourceLength)
25 {
26     HRSRC hSrc;
27     HGLOBAL hRes;
28     PVOID Result;
29 
30     /* find resource */
31     hSrc = FindResourceW(hModule, ResourceName, (LPCWSTR)RT_DIALOG);
32 
33     if (!hSrc)
34     {
35         /* failed to find resource */
36         return NULL;
37     }
38 
39     /* now load the resource */
40     hRes = LoadResource(hAppInstance, hSrc);
41     if (!hRes)
42     {
43         /* failed to load resource */
44         return NULL;
45     }
46 
47     /* now lock the resource */
48     Result = LockResource(hRes);
49 
50     if (!Result)
51     {
52         /* failed to lock resource */
53         return NULL;
54     }
55 
56     if (ResourceLength)
57     {
58         /* store output length */
59         *ResourceLength = SizeofResource(hAppInstance, hSrc);
60     }
61 
62     /* done */
63     return Result;
64 }
65 
66 LPWORD
67 AddDialogControl(
68     IN HWND hwndDialog,
69     OUT HWND *OutWnd,
70     IN LPRECT DialogOffset,
71     IN PDLGITEMTEMPLATE DialogItem,
72     IN DWORD DialogIdMultiplier,
73     IN HFONT hFont,
74     IN UINT xBaseUnit,
75     IN UINT yBaseUnit,
76     IN UINT MixerId)
77 {
78     RECT rect;
79     LPWORD Offset;
80     LPWSTR ClassName, WindowName = NULL;
81     HWND hwnd;
82     DWORD wID;
83     INT nSteps, i;
84 
85     /* initialize client rectangle */
86     rect.left = DialogItem->x;
87     rect.top = DialogItem->y;
88     rect.right = DialogItem->x + DialogItem->cx;
89     rect.bottom = DialogItem->y + DialogItem->cy;
90 
91     /* Convert Dialog units to pixes */
92     ConvertRect(&rect, xBaseUnit, yBaseUnit);
93 
94     rect.left += DialogOffset->left;
95     rect.right += DialogOffset->left;
96     rect.top += DialogOffset->top;
97     rect.bottom += DialogOffset->top;
98 
99     /* move offset after dialog item */
100     Offset = (LPWORD)(DialogItem + 1);
101 
102     if (*Offset == 0xFFFF)
103     {
104         /* class is encoded as type */
105         Offset++;
106 
107         /* get control type */
108         switch(*Offset)
109         {
110             case 0x80:
111                 ClassName = L"button";
112                 WindowName = (LPWSTR)(Offset + 1);
113                 break ;
114             case 0x82:
115                 ClassName = L"static";
116                 WindowName = (LPWSTR)(Offset + 1);
117                 break;
118             default:
119                /* FIXME */
120                assert(0);
121                ClassName = NULL;
122         }
123     }
124     else
125     {
126         /* class name is encoded as string */
127         ClassName = (LPWSTR)Offset;
128 
129         /* move offset to the end of class string */
130         Offset += wcslen(ClassName);
131 
132         /* get window name */
133         WindowName = (LPWSTR)(Offset + 1);
134     }
135 
136     /* move offset past class type/string */
137     Offset++;
138 
139     if (DialogItem->id == MAXWORD)
140     {
141         /* id is not important */
142         wID = DialogItem->id;
143     }
144     else
145     {
146         /* calculate id */
147         wID = DialogItem->id * (DialogIdMultiplier + 1);
148 
149     }
150 
151     /* now create the window */
152     hwnd = CreateWindowExW(DialogItem->dwExtendedStyle,
153                            ClassName,
154                            WindowName,
155                            DialogItem->style,
156                            rect.left,
157                            rect.top,
158                            rect.right - rect.left,
159                            rect.bottom - rect.top,
160                            hwndDialog,
161                            UlongToPtr(wID),
162                            hAppInstance,
163                            NULL);
164 
165     /* sanity check */
166     assert(hwnd);
167 
168     /* store window */
169     *OutWnd = hwnd;
170 
171     /* check if this the track bar */
172     if (!wcsicmp(ClassName, L"msctls_trackbar32"))
173     {
174         if (DialogItem->style & TBS_VERT)
175         {
176             /* Vertical trackbar: Volume */
177 
178             /* Disable the volume trackbar by default */
179             EnableWindow(hwnd, FALSE);
180 
181             /* set up range */
182             SendMessage(hwnd, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(VOLUME_MIN, VOLUME_MAX));
183 
184             /* set up page size */
185             SendMessage(hwnd, TBM_SETPAGESIZE, 0, (LPARAM)VOLUME_PAGE_SIZE);
186 
187             /* set position */
188             SendMessage(hwnd, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)0);
189 
190             /* Calculate and set ticks */
191             nSteps = (VOLUME_MAX / (VOLUME_TICKS + 1));
192             if (VOLUME_MAX % (VOLUME_TICKS + 1) != 0)
193                 nSteps++;
194             for (i = nSteps; i < VOLUME_MAX; i += nSteps)
195                 SendMessage(hwnd, TBM_SETTIC, 0, (LPARAM)i);
196         }
197         else
198         {
199             /* Horizontal trackbar: Balance */
200 
201             /* Disable the balance trackbar by default */
202             EnableWindow(hwnd, FALSE);
203 
204             /* set up range */
205             SendMessage(hwnd, TBM_SETRANGE, (WPARAM)TRUE, (LPARAM)MAKELONG(0, BALANCE_STEPS));
206 
207             /* set up page size */
208             SendMessage(hwnd, TBM_SETPAGESIZE, 0, (LPARAM)BALANCE_PAGE_SIZE);
209 
210             /* set position */
211             SendMessage(hwnd, TBM_SETPOS, (WPARAM)TRUE, (LPARAM)BALANCE_STEPS / 2);
212 
213             /* Calculate and set ticks */
214             nSteps = (BALANCE_STEPS / (BALANCE_TICKS + 1));
215             if (BALANCE_STEPS % (BALANCE_TICKS + 1) != 0)
216                 nSteps++;
217             for (i = nSteps; i < BALANCE_STEPS; i += nSteps)
218                 SendMessage(hwnd, TBM_SETTIC, 0, (LPARAM)i);
219         }
220     }
221     else if (!wcsicmp(ClassName, L"static"))
222     {
223         /* Set font */
224         SendMessageW(hwnd, WM_SETFONT, (WPARAM)hFont, TRUE);
225     }
226     else if (!wcsicmp(ClassName, L"button"))
227     {
228         if (DialogItem->id == IDC_LINE_SWITCH)
229         {
230             if (MixerId == PLAY_MIXER)
231             {
232                 /* Disable checkboxes by default, if we are in play mode */
233                 EnableWindow(hwnd, FALSE);
234             }
235         }
236         else if (DialogItem->id == IDC_LINE_ADVANCED)
237         {
238             ShowWindow(hwnd, SW_HIDE);
239         }
240 
241         /* Set font */
242         SendMessageW(hwnd, WM_SETFONT, (WPARAM)hFont, TRUE);
243     }
244 
245     if (WindowName != NULL)
246     {
247         /* move offset past window name */
248         Offset += wcslen(WindowName) + 1;
249     }
250 
251     /* check if there is additional data */
252     if (*Offset == 0)
253     {
254         /* no additional data */
255         Offset++;
256     }
257     else
258     {
259         /* FIXME: Determine whether this should be "Offset += 1 + *Offset" to explicitly skip the data count too. */
260         /* skip past additional data */
261         Offset += *Offset;
262     }
263 
264     /* make sure next template is word-aligned */
265     Offset = (LPWORD)(((ULONG_PTR)Offset + 3) & ~3);
266 
267     /* done */
268     return Offset;
269 }
270 
271 VOID
272 LoadDialogControls(
273     IN PMIXER_WINDOW MixerWindow,
274     LPRECT DialogOffset,
275     WORD ItemCount,
276     PDLGITEMTEMPLATE DialogItem,
277     DWORD DialogIdMultiplier,
278     UINT xBaseUnit,
279     UINT yBaseUnit)
280 {
281     LPWORD Offset;
282     WORD Index;
283 
284     /* sanity check */
285     assert(ItemCount);
286 
287     if (MixerWindow->Window)
288         MixerWindow->Window = (HWND*)HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MixerWindow->Window, (MixerWindow->WindowCount + ItemCount) * sizeof(HWND));
289     else
290         MixerWindow->Window = (HWND*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ItemCount * sizeof(HWND));
291     if (!MixerWindow->Window)
292     {
293         /* no memory */
294         return;
295     }
296 
297     /* enumerate now all controls */
298     for (Index = 0; Index < ItemCount; Index++)
299     {
300         /* add controls */
301         Offset = AddDialogControl(MixerWindow->hWnd,
302                                   &MixerWindow->Window[MixerWindow->WindowCount],
303                                   DialogOffset,
304                                   DialogItem,
305                                   DialogIdMultiplier,
306                                   MixerWindow->hFont,
307                                   xBaseUnit,
308                                   yBaseUnit,
309                                   MixerWindow->MixerId);
310 
311         /* sanity check */
312         assert(Offset);
313 
314         /* move dialog item to new offset */
315         DialogItem =(PDLGITEMTEMPLATE)Offset;
316 
317         /* increment window count */
318         MixerWindow->WindowCount++;
319     }
320 }
321 
322 VOID
323 LoadDialog(
324     IN HMODULE hModule,
325     IN PMIXER_WINDOW MixerWindow,
326     IN LPCWSTR DialogResId,
327     IN DWORD Index)
328 {
329     LPDLGTEMPLATE DlgTemplate;
330     PDLGITEMTEMPLATE DlgItem;
331     RECT dialogRect;
332     LPWORD Offset;
333     WORD FontSize;
334     WCHAR FontName[100];
335     WORD Length;
336     int width;
337 
338     DWORD units = GetDialogBaseUnits();
339     UINT xBaseUnit = LOWORD(units);
340     UINT yBaseUnit = HIWORD(units);
341 
342     /* first load the dialog resource */
343     DlgTemplate = (LPDLGTEMPLATE)LoadDialogResource(hModule, DialogResId, NULL);
344     if (!DlgTemplate)
345     {
346         /* failed to load resource */
347         return;
348     }
349 
350     /* Now walk past the dialog header */
351     Offset = (LPWORD)(DlgTemplate + 1);
352 
353     /* FIXME: support menu */
354     assert(*Offset == 0);
355     Offset++;
356 
357     /* FIXME: support classes */
358     assert(*Offset == 0);
359     Offset++;
360 
361     /* FIXME: support titles */
362     assert(*Offset == 0);
363     Offset++;
364 
365     /* get font size */
366     FontSize = *Offset;
367     Offset++;
368 
369     /* calculate font length */
370     Length = wcslen((LPWSTR)Offset) + 1;
371     assert(Length < (sizeof(FontName) / sizeof(WCHAR)));
372 
373     /* copy font */
374     wcscpy(FontName, (LPWSTR)Offset);
375 
376     if (DlgTemplate->style & DS_SETFONT)
377     {
378         HDC hDC;
379 
380         hDC = GetDC(0);
381 
382         if (!MixerWindow->hFont)
383         {
384             int pixels = MulDiv(FontSize, GetDeviceCaps(hDC, LOGPIXELSY), 72);
385             MixerWindow->hFont = CreateFontW(-pixels, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FF_DONTCARE, FontName);
386         }
387 
388         if (MixerWindow->hFont)
389         {
390             SIZE charSize;
391             HFONT hOldFont;
392 
393             hOldFont = SelectObject(hDC, MixerWindow->hFont);
394             charSize.cx = GdiGetCharDimensions(hDC, NULL, &charSize.cy);
395             if (charSize.cx)
396             {
397                 xBaseUnit = charSize.cx;
398                 yBaseUnit = charSize.cy;
399             }
400             SelectObject(hDC, hOldFont);
401 
402             MixerWindow->baseUnit.cx = charSize.cx;
403             MixerWindow->baseUnit.cy = charSize.cy;
404         }
405     }
406 
407 //    assert(MixerWindow->hFont);
408 
409     /* move offset after font name */
410     Offset += Length;
411 
412     /* offset is now at first dialog item control */
413     DlgItem = (PDLGITEMTEMPLATE)Offset;
414 
415     dialogRect.left = 0;
416     dialogRect.right = DlgTemplate->cx;
417     dialogRect.top = 0;
418     dialogRect.bottom = DlgTemplate->cy;
419 
420     ConvertRect(&dialogRect, xBaseUnit, yBaseUnit);
421 
422     width = dialogRect.right - dialogRect.left;
423 
424     dialogRect.left += MixerWindow->rect.right;
425     dialogRect.right += MixerWindow->rect.right;
426     dialogRect.top += MixerWindow->rect.top;
427     dialogRect.bottom += MixerWindow->rect.top;
428 
429     MixerWindow->rect.right += width;
430     if ((dialogRect.bottom - dialogRect.top) > (MixerWindow->rect.bottom - MixerWindow->rect.top))
431         MixerWindow->rect.bottom = MixerWindow->rect.top + dialogRect.bottom - dialogRect.top;
432 
433     /* now add the controls */
434     LoadDialogControls(MixerWindow, &dialogRect, DlgTemplate->cdit, DlgItem, Index, xBaseUnit, yBaseUnit);
435 }
436 
437 BOOL
438 CALLBACK
439 EnumConnectionsCallback(
440     PSND_MIXER Mixer,
441     DWORD LineID,
442     LPMIXERLINE Line,
443     PVOID Context)
444 {
445     WCHAR LineName[MIXER_LONG_NAME_CHARS];
446     DWORD Flags;
447     DWORD wID;
448     UINT ControlCount = 0, Index;
449     LPMIXERCONTROL Control = NULL;
450     HWND hDlgCtrl;
451     PMIXERCONTROLDETAILS_UNSIGNED pVolumeDetails = NULL;
452     PPREFERENCES_CONTEXT PrefContext = (PPREFERENCES_CONTEXT)Context;
453 
454     if (Line->cControls == 0)
455         return TRUE;
456 
457     /* get line name */
458     if (SndMixerGetLineName(PrefContext->MixerWindow->Mixer, PrefContext->SelectedLine, LineName, MIXER_LONG_NAME_CHARS, TRUE) == -1)
459     {
460         /* failed to get line name */
461         LineName[0] = L'\0';
462     }
463 
464     pVolumeDetails = HeapAlloc(GetProcessHeap(),
465                                0,
466                                Line->cChannels * sizeof(MIXERCONTROLDETAILS_UNSIGNED));
467     if (pVolumeDetails == NULL)
468         goto done;
469 
470     /* check if line is found in registry settings */
471     if (ReadLineConfig(PrefContext->DeviceName,
472                        LineName,
473                        Line->szName,
474                        &Flags))
475     {
476           /* is it selected */
477           if (Flags != 0x4)
478           {
479               int dlgId;
480 
481               if ((Line->dwComponentType == MIXERLINE_COMPONENTTYPE_DST_SPEAKERS) ||
482                   (Line->dwComponentType == MIXERLINE_COMPONENTTYPE_DST_HEADPHONES))
483                   dlgId = (PrefContext->MixerWindow->Mode == SMALL_MODE) ? IDD_SMALL_MASTER : IDD_NORMAL_MASTER;
484               else
485                   dlgId = (PrefContext->MixerWindow->Mode == SMALL_MODE) ? IDD_SMALL_LINE : IDD_NORMAL_LINE;
486 
487               /* load dialog resource */
488               LoadDialog(hAppInstance, PrefContext->MixerWindow, MAKEINTRESOURCE(dlgId), PrefContext->MixerWindow->DialogCount);
489 
490               /* get id */
491               wID = (PrefContext->MixerWindow->DialogCount + 1) * IDC_LINE_NAME;
492 
493               /* set line name */
494               SetDlgItemTextW(PrefContext->MixerWindow->hWnd, wID, Line->szName);
495 
496               /* query controls */
497               if (SndMixerQueryControls(Mixer, &ControlCount, Line, &Control) != FALSE)
498               {
499                   /* now go through all controls and update their states */
500                   for (Index = 0; Index < Line->cControls; Index++)
501                   {
502                       if (Control[Index].dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE)
503                       {
504                           MIXERCONTROLDETAILS_BOOLEAN Details;
505 
506                           /* get volume control details */
507                           if (SndMixerGetVolumeControlDetails(Mixer, Control[Index].dwControlID, 1, sizeof(MIXERCONTROLDETAILS_BOOLEAN), (LPVOID)&Details) != -1)
508                           {
509                               /* update dialog control */
510                               wID = (PrefContext->MixerWindow->DialogCount + 1) * IDC_LINE_SWITCH;
511 
512                               /* get dialog control */
513                               hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, wID);
514 
515                               if (hDlgCtrl != NULL)
516                               {
517                                   /* Enable the 'Mute' checkbox, if we are in play mode */
518                                   if (Mixer->MixerId == PLAY_MIXER)
519                                       EnableWindow(hDlgCtrl, TRUE);
520 
521                                   /* check state */
522                                   if (SendMessageW(hDlgCtrl, BM_GETCHECK, 0, 0) != Details.fValue)
523                                   {
524                                       /* update control state */
525                                       SendMessageW(hDlgCtrl, BM_SETCHECK, (WPARAM)Details.fValue, 0);
526                                   }
527                               }
528                           }
529                       }
530                       else if (Control[Index].dwControlType == MIXERCONTROL_CONTROLTYPE_VOLUME)
531                       {
532                           /* get volume control details */
533                           if (SndMixerGetVolumeControlDetails(Mixer, Control[Index].dwControlID, Line->cChannels, sizeof(MIXERCONTROLDETAILS_UNSIGNED), (LPVOID)pVolumeDetails) != -1)
534                           {
535                               /* update dialog control */
536                               DWORD volumePosition, volumeStep, maxVolume, i;
537                               DWORD balancePosition, balanceStep;
538 
539                               volumeStep = (Control[Index].Bounds.dwMaximum - Control[Index].Bounds.dwMinimum) / (VOLUME_MAX - VOLUME_MIN);
540 
541                               maxVolume = 0;
542                               for (i = 0; i < Line->cChannels; i++)
543                               {
544                                   if (pVolumeDetails[i].dwValue > maxVolume)
545                                       maxVolume = pVolumeDetails[i].dwValue;
546                               }
547 
548                               volumePosition = (maxVolume - Control[Index].Bounds.dwMinimum) / volumeStep;
549 
550                               if (Line->cChannels == 1)
551                               {
552                                   balancePosition = BALANCE_CENTER;
553                               }
554                               else if (Line->cChannels == 2)
555                               {
556                                   if (pVolumeDetails[0].dwValue == pVolumeDetails[1].dwValue)
557                                   {
558                                       balancePosition = BALANCE_CENTER;
559                                   }
560                                   else if (pVolumeDetails[0].dwValue == Control[Index].Bounds.dwMinimum)
561                                   {
562                                       balancePosition = BALANCE_RIGHT;
563                                   }
564                                   else if (pVolumeDetails[1].dwValue == Control[Index].Bounds.dwMinimum)
565                                   {
566                                       balancePosition = BALANCE_LEFT;
567                                   }
568                                   else
569                                   {
570                                       balanceStep = (maxVolume - Control[Index].Bounds.dwMinimum) / (BALANCE_STEPS / 2);
571 
572                                       if (pVolumeDetails[0].dwValue < pVolumeDetails[1].dwValue)
573                                       {
574                                           balancePosition = (pVolumeDetails[0].dwValue - Control[Index].Bounds.dwMinimum) / balanceStep;
575                                           balancePosition = BALANCE_RIGHT - balancePosition;
576                                       }
577                                       else if (pVolumeDetails[1].dwValue < pVolumeDetails[0].dwValue)
578                                       {
579                                           balancePosition = (pVolumeDetails[1].dwValue - Control[Index].Bounds.dwMinimum) / balanceStep;
580                                           balancePosition = BALANCE_LEFT + balancePosition;
581                                       }
582                                   }
583                               }
584 
585                               /* Set the volume trackbar */
586                               wID = (PrefContext->MixerWindow->DialogCount + 1) * IDC_LINE_SLIDER_VERT;
587 
588                               /* get dialog control */
589                               hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, wID);
590 
591                               if (hDlgCtrl != NULL)
592                               {
593                                   /* check state */
594                                   LRESULT OldPosition = SendMessageW(hDlgCtrl, TBM_GETPOS, 0, 0);
595 
596                                   /* Enable the volume trackbar */
597                                   EnableWindow(hDlgCtrl, TRUE);
598 
599                                   if (OldPosition != (VOLUME_MAX - volumePosition))
600                                   {
601                                       /* update control state */
602                                       SendMessageW(hDlgCtrl, TBM_SETPOS, (WPARAM)TRUE, VOLUME_MAX - volumePosition);
603                                   }
604                               }
605 
606                               if (Line->cChannels == 2)
607                               {
608                                   /* Set the balance trackbar */
609                                   wID = (PrefContext->MixerWindow->DialogCount + 1) * IDC_LINE_SLIDER_HORZ;
610 
611                                   /* get dialog control */
612                                   hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, wID);
613 
614                                   if (hDlgCtrl != NULL)
615                                   {
616                                       /* check state */
617                                       LRESULT OldPosition = SendMessageW(hDlgCtrl, TBM_GETPOS, 0, 0);
618 
619                                       /* Enable the balance trackbar */
620                                       EnableWindow(hDlgCtrl, TRUE);
621 
622                                       if (OldPosition != balancePosition)
623                                       {
624                                           /* update control state */
625                                           SendMessageW(hDlgCtrl, TBM_SETPOS, (WPARAM)TRUE, balancePosition);
626                                       }
627                                   }
628                               }
629                           }
630                       }
631                       else
632                       {
633                           if (PrefContext->MixerWindow->Mode == NORMAL_MODE)
634                               PrefContext->MixerWindow->bHasExtendedControls = TRUE;
635                       }
636                   }
637 
638                   /* free controls */
639                   HeapFree(GetProcessHeap(), 0, Control);
640               }
641 
642               /* increment dialog count */
643               PrefContext->MixerWindow->DialogCount++;
644           }
645     }
646 
647 done:
648     /* Free the volume details */
649     if (pVolumeDetails)
650         HeapFree(GetProcessHeap(), 0, pVolumeDetails);
651 
652     return TRUE;
653 }
654 
655 VOID
656 LoadDialogCtrls(
657     PPREFERENCES_CONTEXT PrefContext)
658 {
659     HWND hDlgCtrl;
660     RECT statusRect;
661 
662     /* set dialog count to zero */
663     PrefContext->MixerWindow->DialogCount = 0;
664 
665     SetRectEmpty(&PrefContext->MixerWindow->rect);
666 
667     /* enumerate controls */
668     SndMixerEnumConnections(PrefContext->MixerWindow->Mixer, PrefContext->SelectedLine, EnumConnectionsCallback, (PVOID)PrefContext);
669 
670     if (PrefContext->MixerWindow->bHasExtendedControls)
671     {
672         EnableMenuItem(GetMenu(PrefContext->MixerWindow->hWnd), IDM_ADVANCED_CONTROLS, MF_BYCOMMAND | MF_ENABLED);
673     }
674 
675     if (PrefContext->MixerWindow->hStatusBar)
676     {
677         GetWindowRect(PrefContext->MixerWindow->hStatusBar, &statusRect);
678         PrefContext->MixerWindow->rect.bottom += (statusRect.bottom - statusRect.top);
679     }
680 
681     /* now move the window */
682     AdjustWindowRect(&PrefContext->MixerWindow->rect, WS_DLGFRAME | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE, TRUE);
683     SetWindowPos(PrefContext->MixerWindow->hWnd, HWND_TOP, PrefContext->MixerWindow->rect.left, PrefContext->MixerWindow->rect.top, PrefContext->MixerWindow->rect.right - PrefContext->MixerWindow->rect.left, PrefContext->MixerWindow->rect.bottom - PrefContext->MixerWindow->rect.top, SWP_NOMOVE | SWP_NOZORDER);
684 
685     /* Move the status bar */
686     if (PrefContext->MixerWindow->hStatusBar)
687     {
688         SetWindowPos(PrefContext->MixerWindow->hStatusBar,
689                      HWND_TOP,
690                      statusRect.left,
691                      PrefContext->MixerWindow->rect.bottom - (statusRect.bottom - statusRect.top),
692                      PrefContext->MixerWindow->rect.right - PrefContext->MixerWindow->rect.left,
693                      statusRect.bottom - statusRect.top,
694                      SWP_NOZORDER);
695     }
696 
697     /* Hide the last line separator */
698     hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, IDC_LINE_SEP * PrefContext->MixerWindow->DialogCount /*PrefContext->Count*/);
699     if (hDlgCtrl != NULL)
700     {
701         ShowWindow(hDlgCtrl, SW_HIDE);
702     }
703 }
704 
705 VOID
706 UpdateDialogLineSwitchControl(
707     PPREFERENCES_CONTEXT PrefContext,
708     LPMIXERLINE Line,
709     LONG fValue)
710 {
711     DWORD Index;
712     DWORD wID;
713     HWND hDlgCtrl;
714     WCHAR LineName[MIXER_LONG_NAME_CHARS];
715 
716     /* find the index of this line */
717     for (Index = 0; Index < PrefContext->MixerWindow->DialogCount; Index++)
718     {
719         /* get id */
720         wID = (Index + 1) * IDC_LINE_NAME;
721 
722         if (GetDlgItemText(PrefContext->MixerWindow->hWnd, wID, LineName, MIXER_LONG_NAME_CHARS) == 0)
723         {
724             /* failed to retrieve id */
725             continue;
726         }
727 
728         /* check if the line name matches */
729         if (!wcsicmp(LineName, Line->szName))
730         {
731             /* found matching line name */
732             wID = (Index + 1) * IDC_LINE_SWITCH;
733 
734             /* get dialog control */
735             hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, wID);
736 
737             if (hDlgCtrl != NULL)
738             {
739                 /* check state */
740                 if (SendMessageW(hDlgCtrl, BM_GETCHECK, 0, 0) != fValue)
741                 {
742                     /* update control state */
743                     SendMessageW(hDlgCtrl, BM_SETCHECK, (WPARAM)fValue, 0);
744                 }
745             }
746             break;
747         }
748     }
749 }
750 
751 VOID
752 UpdateDialogLineSliderControl(
753     PPREFERENCES_CONTEXT PrefContext,
754     LPMIXERLINE Line,
755     DWORD dwDialogID,
756     DWORD Position)
757 {
758     DWORD Index;
759     DWORD wID;
760     HWND hDlgCtrl;
761     WCHAR LineName[MIXER_LONG_NAME_CHARS];
762 
763     /* find the index of this line */
764     for (Index = 0; Index < PrefContext->MixerWindow->DialogCount; Index++)
765     {
766         /* get id */
767         wID = (Index + 1) * IDC_LINE_NAME;
768 
769         if (GetDlgItemText(PrefContext->MixerWindow->hWnd, wID, LineName, MIXER_LONG_NAME_CHARS) == 0)
770         {
771             /* failed to retrieve id */
772             continue;
773         }
774 
775         /* check if the line name matches */
776         if (!wcsicmp(LineName, Line->szName))
777         {
778             /* found matching line name */
779             wID = (Index + 1) * dwDialogID;
780 
781             /* get dialog control */
782             hDlgCtrl = GetDlgItem(PrefContext->MixerWindow->hWnd, wID);
783 
784             if (hDlgCtrl != NULL)
785             {
786                 /* check state */
787                 LRESULT OldPosition = SendMessageW(hDlgCtrl, TBM_GETPOS, 0, 0);
788                 if (OldPosition != Position)
789                 {
790                     /* update control state */
791                     SendMessageW(hDlgCtrl, TBM_SETPOS, (WPARAM)TRUE, Position);
792                 }
793             }
794             break;
795         }
796     }
797 }
798