xref: /reactos/dll/cpl/desk/settings.c (revision 945e8560)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Display Control Panel
4  * PURPOSE:         Settings property page
5  * PROGRAMMERS:     Trevor McCort (lycan359@gmail.com)
6  *                  Hervé Poussineau (hpoussin@reactos.org)
7  */
8 
9 #include "desk.h"
10 
11 typedef struct _SETTINGS_DATA
12 {
13     PDISPLAY_DEVICE_ENTRY DisplayDeviceList;
14     PDISPLAY_DEVICE_ENTRY CurrentDisplayDevice;
15     HBITMAP hSpectrumBitmaps[NUM_SPECTRUM_BITMAPS];
16     int cxSource[NUM_SPECTRUM_BITMAPS];
17     int cySource[NUM_SPECTRUM_BITMAPS];
18 } SETTINGS_DATA, *PSETTINGS_DATA;
19 
20 typedef struct _TIMEOUTDATA
21 {
22     TCHAR szRawBuffer[256];
23     TCHAR szCookedBuffer[256];
24     INT nTimeout;
25 } TIMEOUTDATA, *PTIMEOUTDATA;
26 
27 static VOID
UpdateDisplay(IN HWND hwndDlg,PSETTINGS_DATA pData,IN BOOL bUpdateThumb)28 UpdateDisplay(IN HWND hwndDlg, PSETTINGS_DATA pData, IN BOOL bUpdateThumb)
29 {
30     TCHAR Buffer[64];
31     TCHAR Pixel[64];
32     DWORD index;
33     HWND hwndMonSel;
34     MONSL_MONINFO info;
35 
36     LoadString(hApplet, IDS_PIXEL, Pixel, _countof(Pixel));
37     _stprintf(Buffer, Pixel, pData->CurrentDisplayDevice->CurrentSettings->dmPelsWidth, pData->CurrentDisplayDevice->CurrentSettings->dmPelsHeight, Pixel);
38     SendDlgItemMessage(hwndDlg, IDC_SETTINGS_RESOLUTION_TEXT, WM_SETTEXT, 0, (LPARAM)Buffer);
39 
40     for (index = 0; index < pData->CurrentDisplayDevice->ResolutionsCount; index++)
41     {
42         if (pData->CurrentDisplayDevice->Resolutions[index].dmPelsWidth == pData->CurrentDisplayDevice->CurrentSettings->dmPelsWidth &&
43             pData->CurrentDisplayDevice->Resolutions[index].dmPelsHeight == pData->CurrentDisplayDevice->CurrentSettings->dmPelsHeight)
44         {
45             if (bUpdateThumb)
46                 SendDlgItemMessage(hwndDlg, IDC_SETTINGS_RESOLUTION, TBM_SETPOS, TRUE, index);
47             break;
48         }
49     }
50     if (LoadString(hApplet, (2900 + pData->CurrentDisplayDevice->CurrentSettings->dmBitsPerPel), Buffer, _countof(Buffer)))
51         SendDlgItemMessage(hwndDlg, IDC_SETTINGS_BPP, CB_SELECTSTRING, (WPARAM)-1, (LPARAM)Buffer);
52 
53     hwndMonSel = GetDlgItem(hwndDlg, IDC_SETTINGS_MONSEL);
54     index = (INT)SendMessage(hwndMonSel, MSLM_GETCURSEL, 0, 0);
55     if (index != (DWORD)-1 && SendMessage(hwndMonSel, MSLM_GETMONITORINFO, index, (LPARAM)&info))
56     {
57         info.Size.cx = pData->CurrentDisplayDevice->CurrentSettings->dmPelsWidth;
58         info.Size.cy = pData->CurrentDisplayDevice->CurrentSettings->dmPelsHeight;
59         SendMessage(hwndMonSel, MSLM_SETMONITORINFO, index, (LPARAM)&info);
60     }
61 }
62 
63 static int
CompareSettings(PSETTINGS_ENTRY Entry,DWORD dmPelsWidth,DWORD dmPelsHeight,DWORD dmBitsPerPel,DWORD dmDisplayFrequency)64 CompareSettings(PSETTINGS_ENTRY Entry, DWORD dmPelsWidth, DWORD dmPelsHeight,
65                 DWORD dmBitsPerPel, DWORD dmDisplayFrequency)
66 {
67     if (Entry->dmPelsWidth  == dmPelsWidth  &&
68         Entry->dmPelsHeight == dmPelsHeight &&
69         Entry->dmBitsPerPel == dmBitsPerPel &&
70         Entry->dmDisplayFrequency == dmDisplayFrequency)
71     {
72         return 0;
73     }
74     else
75     if ((Entry->dmPelsWidth  < dmPelsWidth) ||
76         (Entry->dmPelsWidth == dmPelsWidth && Entry->dmPelsHeight < dmPelsHeight) ||
77         (Entry->dmPelsWidth == dmPelsWidth && Entry->dmPelsHeight == dmPelsHeight &&
78          Entry->dmBitsPerPel < dmBitsPerPel))
79     {
80         return 1;
81     }
82     return -1;
83 }
84 
85 static PSETTINGS_ENTRY
GetPossibleSettings(IN LPCTSTR DeviceName,OUT DWORD * pSettingsCount,OUT PSETTINGS_ENTRY * CurrentSettings)86 GetPossibleSettings(IN LPCTSTR DeviceName, OUT DWORD* pSettingsCount, OUT PSETTINGS_ENTRY* CurrentSettings)
87 {
88     DEVMODE devmode;
89     DWORD NbSettings = 0;
90     DWORD iMode = 0;
91     DWORD dwFlags = 0;
92     PSETTINGS_ENTRY Settings = NULL;
93     HDC hDC;
94     PSETTINGS_ENTRY Current;
95     DWORD bpp, xres, yres;
96     DWORD curDispFreq;
97 
98     /* Get current settings */
99     *CurrentSettings = NULL;
100     hDC = CreateIC(NULL, DeviceName, NULL, NULL);
101     bpp = GetDeviceCaps(hDC, PLANES);
102     bpp *= GetDeviceCaps(hDC, BITSPIXEL);
103     xres = GetDeviceCaps(hDC, HORZRES);
104     yres = GetDeviceCaps(hDC, VERTRES);
105     DeleteDC(hDC);
106 
107     /* List all settings */
108     devmode.dmSize = (WORD)sizeof(devmode);
109     devmode.dmDriverExtra = 0;
110 
111     if (!EnumDisplaySettingsEx(DeviceName, ENUM_CURRENT_SETTINGS, &devmode, dwFlags))
112         return NULL;
113 
114     curDispFreq = devmode.dmDisplayFrequency;
115 
116     while (EnumDisplaySettingsEx(DeviceName, iMode, &devmode, dwFlags))
117     {
118         iMode++;
119 
120         if (devmode.dmPelsWidth < 640 ||
121             devmode.dmPelsHeight < 480 ||
122             devmode.dmDisplayFrequency != curDispFreq ||
123             (devmode.dmBitsPerPel != 4 &&
124              devmode.dmBitsPerPel != 8 &&
125              devmode.dmBitsPerPel != 16 &&
126              devmode.dmBitsPerPel != 24 &&
127              devmode.dmBitsPerPel != 32))
128         {
129             continue;
130         }
131 
132         Current = HeapAlloc(GetProcessHeap(), 0, sizeof(SETTINGS_ENTRY));
133         if (Current != NULL)
134         {
135             /* Sort resolutions by increasing height, and BPP */
136             PSETTINGS_ENTRY Previous = NULL;
137             PSETTINGS_ENTRY Next = Settings;
138             Current->dmPelsWidth = devmode.dmPelsWidth;
139             Current->dmPelsHeight = devmode.dmPelsHeight;
140             Current->dmBitsPerPel = devmode.dmBitsPerPel;
141             Current->dmDisplayFrequency = devmode.dmDisplayFrequency;
142             while (Next != NULL &&
143                    CompareSettings(Next, devmode.dmPelsWidth,
144                                    devmode.dmPelsHeight, devmode.dmBitsPerPel,
145                                    devmode.dmDisplayFrequency) > 0)
146             {
147                 Previous = Next;
148                 Next = Next->Flink;
149             }
150             Current->Blink = Previous;
151             Current->Flink = Next;
152             if (Previous == NULL)
153                 Settings = Current;
154             else
155                 Previous->Flink = Current;
156             if (Next != NULL)
157                 Next->Blink = Current;
158             if (devmode.dmPelsWidth == xres && devmode.dmPelsHeight == yres && devmode.dmBitsPerPel == bpp)
159             {
160                 *CurrentSettings = Current;
161             }
162             NbSettings++;
163         }
164     }
165 
166     *pSettingsCount = NbSettings;
167     return Settings;
168 }
169 
170 static BOOL
AddDisplayDevice(IN PSETTINGS_DATA pData,IN const DISPLAY_DEVICE * DisplayDevice)171 AddDisplayDevice(IN PSETTINGS_DATA pData, IN const DISPLAY_DEVICE *DisplayDevice)
172 {
173     PDISPLAY_DEVICE_ENTRY newEntry = NULL;
174     LPTSTR description = NULL;
175     LPTSTR name = NULL;
176     LPTSTR key = NULL;
177     LPTSTR devid = NULL;
178     SIZE_T descriptionSize, nameSize, keySize, devidSize;
179     PSETTINGS_ENTRY Current;
180     DWORD ResolutionsCount = 1;
181     DWORD i;
182 
183     newEntry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DISPLAY_DEVICE_ENTRY));
184     if (!newEntry) goto ByeBye;
185 
186     newEntry->Settings = GetPossibleSettings(DisplayDevice->DeviceName, &newEntry->SettingsCount, &newEntry->CurrentSettings);
187     if (!newEntry->Settings) goto ByeBye;
188 
189     newEntry->InitialSettings.dmPelsWidth = newEntry->CurrentSettings->dmPelsWidth;
190     newEntry->InitialSettings.dmPelsHeight = newEntry->CurrentSettings->dmPelsHeight;
191     newEntry->InitialSettings.dmBitsPerPel = newEntry->CurrentSettings->dmBitsPerPel;
192     newEntry->InitialSettings.dmDisplayFrequency = newEntry->CurrentSettings->dmDisplayFrequency;
193 
194     /* Count different resolutions */
195     for (Current = newEntry->Settings; Current != NULL; Current = Current->Flink)
196     {
197         if (Current->Flink != NULL &&
198             ((Current->dmPelsWidth != Current->Flink->dmPelsWidth) ||
199              (Current->dmPelsHeight != Current->Flink->dmPelsHeight)))
200         {
201             ResolutionsCount++;
202         }
203     }
204 
205     newEntry->Resolutions = HeapAlloc(GetProcessHeap(), 0, ResolutionsCount * sizeof(RESOLUTION_INFO));
206     if (!newEntry->Resolutions) goto ByeBye;
207 
208     newEntry->ResolutionsCount = ResolutionsCount;
209 
210     /* Fill resolutions infos */
211     for (Current = newEntry->Settings, i = 0; Current != NULL; Current = Current->Flink)
212     {
213         if (Current->Flink == NULL ||
214             (Current->Flink != NULL &&
215             ((Current->dmPelsWidth != Current->Flink->dmPelsWidth) ||
216              (Current->dmPelsHeight != Current->Flink->dmPelsHeight))))
217         {
218             newEntry->Resolutions[i].dmPelsWidth = Current->dmPelsWidth;
219             newEntry->Resolutions[i].dmPelsHeight = Current->dmPelsHeight;
220             i++;
221         }
222     }
223     descriptionSize = (_tcslen(DisplayDevice->DeviceString) + 1) * sizeof(TCHAR);
224     description = HeapAlloc(GetProcessHeap(), 0, descriptionSize);
225     if (!description) goto ByeBye;
226 
227     nameSize = (_tcslen(DisplayDevice->DeviceName) + 1) * sizeof(TCHAR);
228     name = HeapAlloc(GetProcessHeap(), 0, nameSize);
229     if (!name) goto ByeBye;
230 
231     keySize = (_tcslen(DisplayDevice->DeviceKey) + 1) * sizeof(TCHAR);
232     key = HeapAlloc(GetProcessHeap(), 0, keySize);
233     if (!key) goto ByeBye;
234 
235     devidSize = (_tcslen(DisplayDevice->DeviceID) + 1) * sizeof(TCHAR);
236     devid = HeapAlloc(GetProcessHeap(), 0, devidSize);
237     if (!devid) goto ByeBye;
238 
239     memcpy(description, DisplayDevice->DeviceString, descriptionSize);
240     memcpy(name, DisplayDevice->DeviceName, nameSize);
241     memcpy(key, DisplayDevice->DeviceKey, keySize);
242     memcpy(devid, DisplayDevice->DeviceID, devidSize);
243     newEntry->DeviceDescription = description;
244     newEntry->DeviceName = name;
245     newEntry->DeviceKey = key;
246     newEntry->DeviceID = devid;
247     newEntry->DeviceStateFlags = DisplayDevice->StateFlags;
248     newEntry->Flink = pData->DisplayDeviceList;
249     pData->DisplayDeviceList = newEntry;
250     return TRUE;
251 
252 ByeBye:
253     if (newEntry != NULL)
254     {
255         if (newEntry->Settings != NULL)
256         {
257             Current = newEntry->Settings;
258             while (Current != NULL)
259             {
260                 PSETTINGS_ENTRY Next = Current->Flink;
261                 HeapFree(GetProcessHeap(), 0, Current);
262                 Current = Next;
263             }
264         }
265         if (newEntry->Resolutions != NULL)
266             HeapFree(GetProcessHeap(), 0, newEntry->Resolutions);
267         HeapFree(GetProcessHeap(), 0, newEntry);
268     }
269     if (description != NULL)
270         HeapFree(GetProcessHeap(), 0, description);
271     if (name != NULL)
272         HeapFree(GetProcessHeap(), 0, name);
273     if (key != NULL)
274         HeapFree(GetProcessHeap(), 0, key);
275     return FALSE;
276 }
277 
278 static VOID
OnDisplayDeviceChanged(IN HWND hwndDlg,IN PSETTINGS_DATA pData,IN PDISPLAY_DEVICE_ENTRY pDeviceEntry)279 OnDisplayDeviceChanged(IN HWND hwndDlg, IN PSETTINGS_DATA pData, IN PDISPLAY_DEVICE_ENTRY pDeviceEntry)
280 {
281     PSETTINGS_ENTRY Current;
282     DWORD index;
283 
284     pData->CurrentDisplayDevice = pDeviceEntry; /* Update variable */
285 
286     /* Fill color depths combo box */
287     SendDlgItemMessage(hwndDlg, IDC_SETTINGS_BPP, CB_RESETCONTENT, 0, 0);
288     for (Current = pDeviceEntry->Settings; Current != NULL; Current = Current->Flink)
289     {
290         TCHAR Buffer[64];
291         if (LoadString(hApplet, (2900 + Current->dmBitsPerPel), Buffer, _countof(Buffer)))
292         {
293             index = (DWORD)SendDlgItemMessage(hwndDlg, IDC_SETTINGS_BPP, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)Buffer);
294             if (index == (DWORD)CB_ERR)
295             {
296                 index = (DWORD)SendDlgItemMessage(hwndDlg, IDC_SETTINGS_BPP, CB_ADDSTRING, 0, (LPARAM)Buffer);
297                 SendDlgItemMessage(hwndDlg, IDC_SETTINGS_BPP, CB_SETITEMDATA, index, Current->dmBitsPerPel);
298             }
299         }
300     }
301 
302     /* Fill device description */
303     SendDlgItemMessage(hwndDlg, IDC_SETTINGS_DEVICE, WM_SETTEXT, 0, (LPARAM)pDeviceEntry->DeviceDescription);
304 
305     /* Fill resolutions slider */
306     SendDlgItemMessage(hwndDlg, IDC_SETTINGS_RESOLUTION, TBM_CLEARTICS, TRUE, 0);
307     SendDlgItemMessage(hwndDlg, IDC_SETTINGS_RESOLUTION, TBM_SETRANGE, TRUE, MAKELONG(0, pDeviceEntry->ResolutionsCount - 1));
308 
309     UpdateDisplay(hwndDlg, pData, TRUE);
310 }
311 
312 static VOID
SettingsOnInitDialog(IN HWND hwndDlg)313 SettingsOnInitDialog(IN HWND hwndDlg)
314 {
315     BITMAP bitmap;
316     DWORD Result = 0;
317     DWORD iDevNum = 0;
318     DWORD i;
319     DISPLAY_DEVICE displayDevice;
320     PSETTINGS_DATA pData;
321 
322     pData = HeapAlloc(GetProcessHeap(), 0, sizeof(SETTINGS_DATA));
323     if (pData == NULL)
324         return;
325 
326     SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pData);
327 
328     /* Get video cards list */
329     pData->DisplayDeviceList = NULL;
330     displayDevice.cb = sizeof(displayDevice);
331     while (EnumDisplayDevices(NULL, iDevNum, &displayDevice, EDD_GET_DEVICE_INTERFACE_NAME))
332     {
333         if ((displayDevice.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) != 0)
334         {
335             if (AddDisplayDevice(pData, &displayDevice))
336                 Result++;
337         }
338         iDevNum++;
339     }
340 
341     if (Result == 0)
342     {
343         /* No adapter found */
344         EnableWindow(GetDlgItem(hwndDlg, IDC_SETTINGS_BPP), FALSE);
345         EnableWindow(GetDlgItem(hwndDlg, IDC_SETTINGS_RESOLUTION), FALSE);
346         EnableWindow(GetDlgItem(hwndDlg, IDC_SETTINGS_RESOLUTION_TEXT), FALSE);
347         EnableWindow(GetDlgItem(hwndDlg, IDC_SETTINGS_ADVANCED), FALSE);
348         ShowWindow(GetDlgItem(hwndDlg, IDC_SETTINGS_SPECTRUM), SW_HIDE);
349 
350         /* Do not initialize the color spectrum bitmaps */
351         memset(pData->hSpectrumBitmaps, 0, sizeof(pData->hSpectrumBitmaps));
352         return;
353     }
354     else if (Result == 1)
355     {
356         MONSL_MONINFO monitors;
357 
358         /* Single video adapter */
359         OnDisplayDeviceChanged(hwndDlg, pData, pData->DisplayDeviceList);
360 
361         ShowWindow(GetDlgItem(hwndDlg, IDC_SETTINGS_MONTEXT), SW_HIDE);
362         ShowWindow(GetDlgItem(hwndDlg, IDC_SETTINGS_MONSEL), SW_HIDE);
363 
364         monitors.Position.x = monitors.Position.y = 0;
365         monitors.Size.cx = pData->CurrentDisplayDevice->CurrentSettings->dmPelsWidth;
366         monitors.Size.cy = pData->CurrentDisplayDevice->CurrentSettings->dmPelsHeight;
367         monitors.Flags = 0;
368         SendDlgItemMessage(hwndDlg,
369                    IDC_SETTINGS_MONSEL,
370                    MSLM_SETMONITORSINFO,
371                    1,
372                    (LPARAM)&monitors);
373     }
374     else /* FIXME: Incomplete! */
375     {
376         PMONSL_MONINFO pMonitors;
377         DWORD i;
378 
379         OnDisplayDeviceChanged(hwndDlg, pData, pData->DisplayDeviceList);
380 
381         ShowWindow(GetDlgItem(hwndDlg, IDC_RESOLUTION_PREVIEW), SW_HIDE);
382 
383         pMonitors = (PMONSL_MONINFO)HeapAlloc(GetProcessHeap(), 0, sizeof(MONSL_MONINFO) * Result);
384         if (pMonitors)
385         {
386             DWORD hack = 1280;
387             for (i = 0; i < Result; i++)
388             {
389                 pMonitors[i].Position.x = hack * i;
390                 pMonitors[i].Position.y = 0;
391                 pMonitors[i].Size.cx = pData->DisplayDeviceList->CurrentSettings->dmPelsWidth;
392                 pMonitors[i].Size.cy = pData->DisplayDeviceList->CurrentSettings->dmPelsHeight;
393                 pMonitors[i].Flags = 0;
394             }
395 
396             SendDlgItemMessage(hwndDlg,
397                        IDC_SETTINGS_MONSEL,
398                        MSLM_SETMONITORSINFO,
399                        Result,
400                        (LPARAM)pMonitors);
401 
402             HeapFree(GetProcessHeap(), 0, pMonitors);
403         }
404     }
405 
406     /* Initialize the color spectrum bitmaps */
407     for (i = 0; i < NUM_SPECTRUM_BITMAPS; i++)
408     {
409         pData->hSpectrumBitmaps[i] = LoadImageW(hApplet, MAKEINTRESOURCEW(IDB_SPECTRUM_4 + i), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
410 
411         if (pData->hSpectrumBitmaps[i] != NULL)
412         {
413             if (GetObjectW(pData->hSpectrumBitmaps[i], sizeof(BITMAP), &bitmap) != 0)
414             {
415                 pData->cxSource[i] = bitmap.bmWidth;
416                 pData->cySource[i] = bitmap.bmHeight;
417             }
418             else
419             {
420                 pData->cxSource[i] = 0;
421                 pData->cySource[i] = 0;
422             }
423         }
424     }
425 }
426 
427 static VOID
ShowResolutionPreview(IN LPDRAWITEMSTRUCT draw,IN PSETTINGS_DATA pData)428 ShowResolutionPreview(IN LPDRAWITEMSTRUCT draw, IN PSETTINGS_DATA pData)
429 {
430     HBRUSH hBrush;
431     HDC hDC;
432     HGDIOBJ hOldObj;
433     RECT rcItem = {
434         MONITOR_LEFT,
435         MONITOR_TOP,
436         MONITOR_RIGHT,
437         MONITOR_BOTTOM
438     };
439 
440     hDC = CreateCompatibleDC(draw->hDC);
441     hOldObj = SelectObject(hDC, g_GlobalData.hMonitorBitmap);
442 
443     /* FIXME: Draw resolution preview bitmap inside monitor. */
444     hBrush = CreateSolidBrush(g_GlobalData.desktop_color);
445     FillRect(hDC, &rcItem, hBrush);
446     DeleteObject(hBrush);
447 
448     GdiTransparentBlt(draw->hDC,
449                       draw->rcItem.left, draw->rcItem.top,
450                       draw->rcItem.right - draw->rcItem.left + 1,
451                       draw->rcItem.bottom - draw->rcItem.top + 1,
452                       hDC,
453                       0, 0,
454                       g_GlobalData.bmMonWidth, g_GlobalData.bmMonHeight,
455                       MONITOR_ALPHA);
456 
457     SelectObject(hDC, hOldObj);
458     DeleteDC(hDC);
459 }
460 
461 /* Get the ID for SETTINGS_DATA::hSpectrumBitmaps */
462 static VOID
ShowColorSpectrum(IN HDC hDC,IN LPRECT client,IN DWORD BitsPerPel,IN PSETTINGS_DATA pData)463 ShowColorSpectrum(IN HDC hDC, IN LPRECT client, IN DWORD BitsPerPel, IN PSETTINGS_DATA pData)
464 {
465     HDC hdcMem;
466     INT iBitmap;
467 
468     hdcMem = CreateCompatibleDC(hDC);
469 
470     if (!hdcMem)
471         return;
472 
473     switch(BitsPerPel)
474     {
475         case 4:  iBitmap = 0; break;
476         case 8:  iBitmap = 1; break;
477         default: iBitmap = 2;
478     }
479 
480     if (SelectObject(hdcMem, pData->hSpectrumBitmaps[iBitmap]))
481     {
482         StretchBlt(hDC,
483                client->left, client->top,
484                client->right - client->left,
485                client->bottom - client->top,
486                hdcMem, 0, 0,
487                pData->cxSource[iBitmap],
488                pData->cySource[iBitmap], SRCCOPY);
489     }
490 
491     DeleteDC(hdcMem);
492 }
493 
494 static VOID
OnBPPChanged(IN HWND hwndDlg,IN PSETTINGS_DATA pData)495 OnBPPChanged(IN HWND hwndDlg, IN PSETTINGS_DATA pData)
496 {
497     /* If new BPP is not compatible with resolution:
498      * 1) try to find the nearest smaller matching resolution
499      * 2) otherwise, get the nearest bigger resolution
500      */
501     PSETTINGS_ENTRY Current;
502     DWORD dmNewBitsPerPel;
503     DWORD index;
504     HDC hSpectrumDC;
505     HWND hSpectrumControl;
506     RECT client;
507 
508     index = (DWORD)SendDlgItemMessage(hwndDlg, IDC_SETTINGS_BPP, CB_GETCURSEL, 0, 0);
509     dmNewBitsPerPel = (DWORD)SendDlgItemMessage(hwndDlg, IDC_SETTINGS_BPP, CB_GETITEMDATA, index, 0);
510 
511     /* Show a new spectrum bitmap */
512     hSpectrumControl = GetDlgItem(hwndDlg, IDC_SETTINGS_SPECTRUM);
513     hSpectrumDC = GetDC(hSpectrumControl);
514     if (hSpectrumDC == NULL)
515         return;
516 
517     GetClientRect(hSpectrumControl, &client);
518     ShowColorSpectrum(hSpectrumDC, &client, dmNewBitsPerPel, pData);
519     ReleaseDC(hSpectrumControl, hSpectrumDC);
520 
521     /* Find if new parameters are valid */
522     Current = pData->CurrentDisplayDevice->CurrentSettings;
523     if (dmNewBitsPerPel == Current->dmBitsPerPel)
524     {
525         /* No change */
526         return;
527     }
528 
529     PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
530 
531     if (dmNewBitsPerPel < Current->dmBitsPerPel)
532     {
533         Current = Current->Blink;
534         while (Current != NULL)
535         {
536             if (Current->dmBitsPerPel == dmNewBitsPerPel
537              && Current->dmPelsHeight == pData->CurrentDisplayDevice->CurrentSettings->dmPelsHeight
538              && Current->dmPelsWidth == pData->CurrentDisplayDevice->CurrentSettings->dmPelsWidth)
539             {
540                 pData->CurrentDisplayDevice->CurrentSettings = Current;
541                 UpdateDisplay(hwndDlg, pData, TRUE);
542                 return;
543             }
544             Current = Current->Blink;
545         }
546     }
547     else
548     {
549         Current = Current->Flink;
550         while (Current != NULL)
551         {
552             if (Current->dmBitsPerPel == dmNewBitsPerPel
553              && Current->dmPelsHeight == pData->CurrentDisplayDevice->CurrentSettings->dmPelsHeight
554              && Current->dmPelsWidth == pData->CurrentDisplayDevice->CurrentSettings->dmPelsWidth)
555             {
556                 pData->CurrentDisplayDevice->CurrentSettings = Current;
557                 UpdateDisplay(hwndDlg, pData, TRUE);
558                 return;
559             }
560             Current = Current->Flink;
561         }
562     }
563 
564     /* Search smaller resolution compatible with current color depth */
565     Current = pData->CurrentDisplayDevice->CurrentSettings->Blink;
566     while (Current != NULL)
567     {
568         if (Current->dmBitsPerPel == dmNewBitsPerPel)
569         {
570             pData->CurrentDisplayDevice->CurrentSettings = Current;
571             UpdateDisplay(hwndDlg, pData, TRUE);
572             return;
573         }
574         Current = Current->Blink;
575     }
576 
577     /* Search bigger resolution compatible with current color depth */
578     Current = pData->CurrentDisplayDevice->CurrentSettings->Flink;
579     while (Current != NULL)
580     {
581         if (Current->dmBitsPerPel == dmNewBitsPerPel)
582         {
583             pData->CurrentDisplayDevice->CurrentSettings = Current;
584             UpdateDisplay(hwndDlg, pData, TRUE);
585             return;
586         }
587         Current = Current->Flink;
588     }
589 
590     /* We shouldn't go there */
591 }
592 
593 static VOID
OnResolutionChanged(IN HWND hwndDlg,IN PSETTINGS_DATA pData,IN DWORD NewPosition,IN BOOL bUpdateThumb)594 OnResolutionChanged(IN HWND hwndDlg, IN PSETTINGS_DATA pData, IN DWORD NewPosition,
595                     IN BOOL bUpdateThumb)
596 {
597     /* If new resolution is not compatible with color depth:
598      * 1) try to find the nearest bigger matching color depth
599      * 2) otherwise, get the nearest smaller color depth
600      */
601     PSETTINGS_ENTRY Current;
602     DWORD dmNewPelsHeight = pData->CurrentDisplayDevice->Resolutions[NewPosition].dmPelsHeight;
603     DWORD dmNewPelsWidth = pData->CurrentDisplayDevice->Resolutions[NewPosition].dmPelsWidth;
604     DWORD dmBitsPerPel;
605     DWORD dmDisplayFrequency;
606 
607     /* Find if new parameters are valid */
608     Current = pData->CurrentDisplayDevice->CurrentSettings;
609     if (dmNewPelsHeight == Current->dmPelsHeight && dmNewPelsWidth == Current->dmPelsWidth)
610     {
611         /* No change */
612         return;
613     }
614 
615     PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
616     InvalidateRect(GetDlgItem(hwndDlg, IDC_RESOLUTION_PREVIEW), NULL, TRUE);
617 
618     dmBitsPerPel = Current->dmBitsPerPel;
619     dmDisplayFrequency = Current->dmDisplayFrequency;
620 
621     if (CompareSettings(Current, dmNewPelsWidth,
622                         dmNewPelsHeight, dmBitsPerPel,
623                         dmDisplayFrequency) < 0)
624     {
625         Current = Current->Blink;
626         while (Current != NULL)
627         {
628             if (Current->dmPelsHeight == dmNewPelsHeight
629              && Current->dmPelsWidth  == dmNewPelsWidth
630              && Current->dmBitsPerPel == dmBitsPerPel)
631             {
632                 pData->CurrentDisplayDevice->CurrentSettings = Current;
633                 UpdateDisplay(hwndDlg, pData, bUpdateThumb);
634                 return;
635             }
636             Current = Current->Blink;
637         }
638     }
639     else
640     {
641         Current = Current->Flink;
642         while (Current != NULL)
643         {
644             if (Current->dmPelsHeight == dmNewPelsHeight
645              && Current->dmPelsWidth  == dmNewPelsWidth
646              && Current->dmBitsPerPel == dmBitsPerPel)
647             {
648                 pData->CurrentDisplayDevice->CurrentSettings = Current;
649                 UpdateDisplay(hwndDlg, pData, bUpdateThumb);
650                 return;
651             }
652             Current = Current->Flink;
653         }
654     }
655 
656     /* Search bigger color depth compatible with current resolution */
657     Current = pData->CurrentDisplayDevice->CurrentSettings->Flink;
658     while (Current != NULL)
659     {
660         if (dmNewPelsHeight == Current->dmPelsHeight && dmNewPelsWidth == Current->dmPelsWidth)
661         {
662             pData->CurrentDisplayDevice->CurrentSettings = Current;
663             UpdateDisplay(hwndDlg, pData, bUpdateThumb);
664             return;
665         }
666         Current = Current->Flink;
667     }
668 
669     /* Search smaller color depth compatible with current resolution */
670     Current = pData->CurrentDisplayDevice->CurrentSettings->Blink;
671     while (Current != NULL)
672     {
673         if (dmNewPelsHeight == Current->dmPelsHeight && dmNewPelsWidth == Current->dmPelsWidth)
674         {
675             pData->CurrentDisplayDevice->CurrentSettings = Current;
676             UpdateDisplay(hwndDlg, pData, bUpdateThumb);
677             return;
678         }
679         Current = Current->Blink;
680     }
681 
682     /* We shouldn't go there */
683 }
684 
685 /* Property sheet page callback */
686 UINT CALLBACK
SettingsPageCallbackProc(HWND hwnd,UINT uMsg,LPPROPSHEETPAGE ppsp)687 SettingsPageCallbackProc(HWND hwnd, UINT uMsg, LPPROPSHEETPAGE ppsp)
688 {
689     UINT Ret = 0;
690 
691     switch (uMsg)
692     {
693         case PSPCB_CREATE:
694             Ret = RegisterMonitorSelectionControl(hApplet);
695             break;
696 
697         case PSPCB_RELEASE:
698             UnregisterMonitorSelectionControl(hApplet);
699             break;
700     }
701 
702     return Ret;
703 }
704 
705 static INT_PTR CALLBACK
ConfirmDlgProc(IN HWND hwndDlg,IN UINT uMsg,IN WPARAM wParam,IN LPARAM lParam)706 ConfirmDlgProc(IN HWND hwndDlg, IN UINT uMsg, IN WPARAM wParam, IN LPARAM lParam)
707 {
708     PTIMEOUTDATA pData;
709 
710     pData = (PTIMEOUTDATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
711 
712     switch(uMsg)
713     {
714         case WM_INITDIALOG:
715             /* Allocate the local dialog data */
716             pData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(TIMEOUTDATA));
717             if (pData == NULL)
718                 return FALSE;
719 
720             /* Link the dialog data to the dialog */
721             SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)pData);
722 
723             /* Timeout in seconds */
724             pData->nTimeout = 15;
725 
726             /* Load the raw timeout string */
727             LoadString(hApplet, IDS_TIMEOUTTEXT, pData->szRawBuffer, _countof(pData->szRawBuffer));
728 
729             /* Cook the timeout string and show it */
730             _stprintf(pData->szCookedBuffer, pData->szRawBuffer, pData->nTimeout);
731             SetDlgItemText(hwndDlg, IDC_TIMEOUTTEXT, pData->szCookedBuffer);
732 
733             /* Start the timer (ticks every second)*/
734             SetTimer(hwndDlg, 1, 1000, NULL);
735             break;
736 
737         case WM_TIMER:
738             /* Update the timepout value */
739             pData->nTimeout--;
740 
741             /* Update the timeout text */
742             _stprintf(pData->szCookedBuffer, pData->szRawBuffer, pData->nTimeout);
743             SetDlgItemText(hwndDlg, IDC_TIMEOUTTEXT, pData->szCookedBuffer);
744 
745             /* Kill the timer and return a 'No', if we ran out of time */
746             if (pData->nTimeout == 0)
747             {
748                 KillTimer(hwndDlg, 1);
749                 EndDialog(hwndDlg, IDNO);
750             }
751             break;
752 
753         case WM_COMMAND:
754             /* Kill the timer and return the clicked button id */
755             KillTimer(hwndDlg, 1);
756             EndDialog(hwndDlg, LOWORD(wParam));
757             break;
758 
759         case WM_DESTROY:
760             /* Free the local dialog data */
761             HeapFree(GetProcessHeap(), 0, pData);
762             break;
763     }
764 
765     return FALSE;
766 }
767 
768 BOOL
SwitchDisplayMode(HWND hwndDlg,PWSTR DeviceName,PSETTINGS_ENTRY seInit,PSETTINGS_ENTRY seNew,OUT PLONG rc)769 SwitchDisplayMode(HWND hwndDlg, PWSTR DeviceName, PSETTINGS_ENTRY seInit, PSETTINGS_ENTRY seNew, OUT PLONG rc)
770 {
771     TCHAR Message[1024], Title[256];
772     DEVMODE devmode;
773 
774     RtlZeroMemory(&devmode, sizeof(devmode));
775     devmode.dmSize = (WORD)sizeof(devmode);
776     devmode.dmPelsWidth = seNew->dmPelsWidth;
777     devmode.dmPelsHeight = seNew->dmPelsHeight;
778     devmode.dmBitsPerPel = seNew->dmBitsPerPel;
779     devmode.dmDisplayFrequency = seNew->dmDisplayFrequency;
780     devmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY;
781 
782     *rc = ChangeDisplaySettingsEx(DeviceName,
783                                   &devmode,
784                                   NULL,
785                                   CDS_UPDATEREGISTRY,
786                                   NULL);
787     switch (*rc)
788     {
789         case DISP_CHANGE_SUCCESSFUL:
790             break;
791 
792         case DISP_CHANGE_RESTART:
793             LoadString(hApplet, IDS_DISPLAY_SETTINGS, Title, _countof(Title));
794             LoadString(hApplet, IDS_APPLY_NEEDS_RESTART, Message, _countof(Message));
795             MessageBox(hwndDlg, Message, Title, MB_OK | MB_ICONINFORMATION);
796             return FALSE;
797 
798         case DISP_CHANGE_FAILED:
799         default:
800             LoadString(hApplet, IDS_DISPLAY_SETTINGS, Title, _countof(Title));
801             LoadString(hApplet, IDS_APPLY_FAILED, Message, _countof(Message));
802             MessageBox(hwndDlg, Message, Title, MB_OK | MB_ICONSTOP);
803             return FALSE;
804     }
805 
806     if (DialogBox(hApplet, MAKEINTRESOURCE(IDD_CONFIRMSETTINGS), hwndDlg, ConfirmDlgProc) == IDYES)
807     {
808         return TRUE;
809     }
810     else
811     {
812         devmode.dmPelsWidth = seInit->dmPelsWidth;
813         devmode.dmPelsHeight = seInit->dmPelsHeight;
814         devmode.dmBitsPerPel = seInit->dmBitsPerPel;
815         devmode.dmDisplayFrequency = seInit->dmDisplayFrequency;
816 
817         *rc = ChangeDisplaySettingsEx(DeviceName,
818                                       &devmode,
819                                       NULL,
820                                       CDS_UPDATEREGISTRY,
821                                       NULL);
822         switch (*rc)
823         {
824             case DISP_CHANGE_SUCCESSFUL:
825                 return FALSE;
826 
827             case DISP_CHANGE_RESTART:
828                 LoadString(hApplet, IDS_DISPLAY_SETTINGS, Title, _countof(Title));
829                 LoadString(hApplet, IDS_APPLY_NEEDS_RESTART, Message, _countof(Message));
830                 MessageBox(hwndDlg, Message, Title, MB_OK | MB_ICONINFORMATION);
831                 return FALSE;
832 
833             case DISP_CHANGE_FAILED:
834             default:
835                 LoadString(hApplet, IDS_DISPLAY_SETTINGS, Title, _countof(Title));
836                 LoadString(hApplet, IDS_APPLY_FAILED, Message, _countof(Message));
837                 MessageBox(hwndDlg, Message, Title, MB_OK | MB_ICONSTOP);
838                 return FALSE;
839         }
840     }
841 }
842 
843 static
844 PSETTINGS_ENTRY
FindBestElement(_In_ PDISPLAY_DEVICE_ENTRY pDevice)845 FindBestElement(
846     _In_ PDISPLAY_DEVICE_ENTRY pDevice)
847 {
848     PSETTINGS_ENTRY Request = &pDevice->InitialSettings, BestEntry = NULL, Current;
849     LONG Distance, NearestDistance = MAXLONG;
850 
851     /* Find the best entry in the list */
852     for (Current = pDevice->Settings; Current; Current = Current->Flink)
853     {
854         Distance = 0x100000 * labs(Current->dmBitsPerPel       - Request->dmBitsPerPel      ) +
855                       0x100 * labs(Current->dmPelsWidth        - Request->dmPelsWidth       ) +
856                       0x100 * labs(Current->dmPelsHeight       - Request->dmPelsHeight      ) +
857                               labs(Current->dmDisplayFrequency - Request->dmDisplayFrequency);
858         if (Distance == 0)
859             return Current;
860 
861         if (Distance < NearestDistance)
862         {
863             BestEntry = Current;
864             NearestDistance = Distance;
865         }
866     }
867 
868     return BestEntry;
869 }
870 
871 static VOID
ApplyDisplaySettings(HWND hwndDlg,PSETTINGS_DATA pData)872 ApplyDisplaySettings(HWND hwndDlg, PSETTINGS_DATA pData)
873 {
874     BOOL Ret;
875     LONG rc;
876 
877     Ret = SwitchDisplayMode(hwndDlg,
878                             pData->CurrentDisplayDevice->DeviceName,
879                             &pData->CurrentDisplayDevice->InitialSettings,
880                             pData->CurrentDisplayDevice->CurrentSettings,
881                             &rc);
882 
883     if (rc != DISP_CHANGE_SUCCESSFUL)
884         return;
885 
886     if (Ret)
887     {
888         pData->CurrentDisplayDevice->InitialSettings.dmPelsWidth = pData->CurrentDisplayDevice->CurrentSettings->dmPelsWidth;
889         pData->CurrentDisplayDevice->InitialSettings.dmPelsHeight = pData->CurrentDisplayDevice->CurrentSettings->dmPelsHeight;
890         pData->CurrentDisplayDevice->InitialSettings.dmBitsPerPel = pData->CurrentDisplayDevice->CurrentSettings->dmBitsPerPel;
891         pData->CurrentDisplayDevice->InitialSettings.dmDisplayFrequency = pData->CurrentDisplayDevice->CurrentSettings->dmDisplayFrequency;
892     }
893     else
894     {
895         pData->CurrentDisplayDevice->CurrentSettings = FindBestElement(pData->CurrentDisplayDevice);
896         UpdateDisplay(hwndDlg, pData, TRUE);
897     }
898 }
899 
900 /* Property page dialog callback */
901 INT_PTR CALLBACK
SettingsPageProc(IN HWND hwndDlg,IN UINT uMsg,IN WPARAM wParam,IN LPARAM lParam)902 SettingsPageProc(IN HWND hwndDlg, IN UINT uMsg, IN WPARAM wParam, IN LPARAM lParam)
903 {
904     PSETTINGS_DATA pData;
905 
906     pData = (PSETTINGS_DATA)GetWindowLongPtr(hwndDlg, DWLP_USER);
907 
908     switch(uMsg)
909     {
910         case WM_INITDIALOG:
911         {
912             SettingsOnInitDialog(hwndDlg);
913             break;
914         }
915         case WM_DRAWITEM:
916         {
917             LPDRAWITEMSTRUCT lpDrawItem;
918             lpDrawItem = (LPDRAWITEMSTRUCT)lParam;
919 
920             switch (lpDrawItem->CtlID)
921             {
922                 case IDC_RESOLUTION_PREVIEW:
923                 {
924                     ShowResolutionPreview(lpDrawItem, pData);
925                     break;
926                 }
927                 case IDC_SETTINGS_SPECTRUM:
928                 {
929                     ShowColorSpectrum(lpDrawItem->hDC, &lpDrawItem->rcItem, pData->CurrentDisplayDevice->CurrentSettings->dmBitsPerPel, pData);
930                     break;
931                 }
932             }
933             break;
934         }
935         case WM_COMMAND:
936         {
937             DWORD controlId = LOWORD(wParam);
938             DWORD command   = HIWORD(wParam);
939 
940             if (controlId == IDC_SETTINGS_ADVANCED && command == BN_CLICKED)
941             {
942                 if (DisplayAdvancedSettings(hwndDlg, pData->CurrentDisplayDevice))
943                 {
944                     DEVMODE devmode;
945                     ZeroMemory(&devmode, sizeof(devmode));
946                     devmode.dmSize = (WORD)sizeof(devmode);
947                     if (EnumDisplaySettingsExW(pData->CurrentDisplayDevice->DeviceName,
948                                                ENUM_CURRENT_SETTINGS, &devmode, 0))
949                     {
950                         PSETTINGS_ENTRY pInitialSettings = &pData->CurrentDisplayDevice->InitialSettings;
951                         pInitialSettings->dmPelsWidth = devmode.dmPelsWidth;
952                         pInitialSettings->dmPelsHeight = devmode.dmPelsHeight;
953                         pInitialSettings->dmBitsPerPel = devmode.dmBitsPerPel;
954                         pInitialSettings->dmDisplayFrequency = devmode.dmDisplayFrequency;
955                         pData->CurrentDisplayDevice->CurrentSettings =
956                             FindBestElement(pData->CurrentDisplayDevice);
957                         UpdateDisplay(hwndDlg, pData, TRUE);
958                     }
959                 }
960             }
961             else if (controlId == IDC_SETTINGS_BPP && command == CBN_SELCHANGE)
962                 OnBPPChanged(hwndDlg, pData);
963             break;
964         }
965         case WM_HSCROLL:
966         {
967             switch (LOWORD(wParam))
968             {
969                 case TB_LINEUP:
970                 case TB_LINEDOWN:
971                 case TB_PAGEUP:
972                 case TB_PAGEDOWN:
973                 case TB_TOP:
974                 case TB_BOTTOM:
975                 case TB_ENDTRACK:
976                 {
977                     DWORD newPosition = (DWORD)SendDlgItemMessage(hwndDlg, IDC_SETTINGS_RESOLUTION, TBM_GETPOS, 0, 0);
978                     OnResolutionChanged(hwndDlg, pData, newPosition, TRUE);
979                     break;
980                 }
981 
982                 case TB_THUMBTRACK:
983                     OnResolutionChanged(hwndDlg, pData, HIWORD(wParam), FALSE);
984                     break;
985             }
986             break;
987         }
988         case WM_NOTIFY:
989         {
990             LPNMHDR lpnm = (LPNMHDR)lParam;
991             if (lpnm->code == (UINT)PSN_APPLY)
992             {
993                 if (pData->CurrentDisplayDevice->CurrentSettings->dmPelsWidth != pData->CurrentDisplayDevice->InitialSettings.dmPelsWidth
994                  || pData->CurrentDisplayDevice->CurrentSettings->dmPelsHeight != pData->CurrentDisplayDevice->InitialSettings.dmPelsHeight
995                  || pData->CurrentDisplayDevice->CurrentSettings->dmBitsPerPel != pData->CurrentDisplayDevice->InitialSettings.dmBitsPerPel)
996                 {
997                     /* Apply new settings */
998                     ApplyDisplaySettings(hwndDlg, pData);
999                 }
1000             }
1001             else if (lpnm->code == MSLN_MONITORCHANGED)
1002             {
1003                 PMONSL_MONNMMONITORCHANGING lpnmi = (PMONSL_MONNMMONITORCHANGING)lParam;
1004                 PDISPLAY_DEVICE_ENTRY Current = pData->DisplayDeviceList;
1005                 ULONG i;
1006                 for (i = 0; i < lpnmi->hdr.Index; i++)
1007                     Current = Current->Flink;
1008                 OnDisplayDeviceChanged(hwndDlg, pData, Current);
1009             }
1010             break;
1011         }
1012 
1013         case WM_CONTEXTMENU:
1014         {
1015             HWND hwndMonSel;
1016             HMENU hPopup;
1017             UINT uiCmd;
1018             POINT pt, ptClient;
1019             INT Index;
1020 
1021             pt.x = (SHORT)LOWORD(lParam);
1022             pt.y = (SHORT)HIWORD(lParam);
1023 
1024             hwndMonSel = GetDlgItem(hwndDlg, IDC_SETTINGS_MONSEL);
1025             if ((HWND)wParam == hwndMonSel)
1026             {
1027                 if (pt.x == -1 && pt.y == -1)
1028                 {
1029                     RECT rcMon;
1030 
1031                     Index = (INT)SendMessage(hwndMonSel,
1032                                              MSLM_GETCURSEL,
1033                                              0,
1034                                              0);
1035 
1036                     if (Index >= 0 &&
1037                         (INT)SendMessage(hwndMonSel,
1038                                          MSLM_GETMONITORRECT,
1039                                          Index,
1040                                          (LPARAM)&rcMon) > 0)
1041                     {
1042                         pt.x = rcMon.left + ((rcMon.right - rcMon.left) / 2);
1043                         pt.y = rcMon.top + ((rcMon.bottom - rcMon.top) / 2);
1044                     }
1045                     else
1046                         pt.x = pt.y = 0;
1047 
1048                     MapWindowPoints(hwndMonSel, NULL, &pt, 1);
1049                 }
1050                 else
1051                 {
1052                     ptClient = pt;
1053                     MapWindowPoints(NULL, hwndMonSel, &ptClient, 1);
1054 
1055                     Index = (INT)SendMessage(hwndMonSel,
1056                                              MSLM_HITTEST,
1057                                              (WPARAM)&ptClient,
1058                                              0);
1059                 }
1060 
1061                 if (Index >= 0)
1062                 {
1063                     hPopup = LoadPopupMenu(hApplet,
1064                                            MAKEINTRESOURCE(IDM_MONITOR_MENU));
1065                     if (hPopup != NULL)
1066                     {
1067                         /* FIXME: Enable/Disable menu items */
1068                         EnableMenuItem(hPopup,
1069                                        ID_MENU_ATTACHED,
1070                                        MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
1071                         EnableMenuItem(hPopup,
1072                                        ID_MENU_PRIMARY,
1073                                        MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
1074                         EnableMenuItem(hPopup,
1075                                        ID_MENU_IDENTIFY,
1076                                        MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
1077                         EnableMenuItem(hPopup,
1078                                        ID_MENU_PROPERTIES,
1079                                        MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
1080 
1081                         uiCmd = (UINT)TrackPopupMenu(hPopup,
1082                                                      TPM_RETURNCMD | TPM_RIGHTBUTTON,
1083                                                      pt.x,
1084                                                      pt.y,
1085                                                      0,
1086                                                      hwndDlg,
1087                                                      NULL);
1088 
1089                         switch (uiCmd)
1090                         {
1091                             case ID_MENU_ATTACHED:
1092                             case ID_MENU_PRIMARY:
1093                             case ID_MENU_IDENTIFY:
1094                             case ID_MENU_PROPERTIES:
1095                                 /* FIXME: Implement */
1096                                 break;
1097                         }
1098 
1099                         DestroyMenu(hPopup);
1100                     }
1101                 }
1102             }
1103             break;
1104         }
1105 
1106         case WM_DESTROY:
1107         {
1108             DWORD i;
1109             PDISPLAY_DEVICE_ENTRY Current = pData->DisplayDeviceList;
1110 
1111             while (Current != NULL)
1112             {
1113                 PDISPLAY_DEVICE_ENTRY Next = Current->Flink;
1114                 PSETTINGS_ENTRY CurrentSettings = Current->Settings;
1115                 while (CurrentSettings != NULL)
1116                 {
1117                     PSETTINGS_ENTRY NextSettings = CurrentSettings->Flink;
1118                     HeapFree(GetProcessHeap(), 0, CurrentSettings);
1119                     CurrentSettings = NextSettings;
1120                 }
1121                 HeapFree(GetProcessHeap(), 0, Current);
1122                 Current = Next;
1123             }
1124 
1125             for (i = 0; i < NUM_SPECTRUM_BITMAPS; i++)
1126             {
1127                 if (pData->hSpectrumBitmaps[i])
1128                     DeleteObject(pData->hSpectrumBitmaps[i]);
1129             }
1130 
1131             HeapFree(GetProcessHeap(), 0, pData);
1132         }
1133     }
1134     return FALSE;
1135 }
1136