[DESK.CPL] Appearance: Fixup control positions after font metrics fix
[reactos.git] / dll / cpl / desk / monslctl.c
1 #include "desk.h"
2
3 static const TCHAR szMonitorSelWndClass[] = TEXT("MONITORSELWNDCLASS");
4
5 typedef struct _MONSL_MON
6 {
7 RECT rc;
8 HFONT hFont;
9 TCHAR szCaption[12];
10 } MONSL_MON, *PMONSL_MON;
11
12 typedef struct _MONITORSELWND
13 {
14 HWND hSelf;
15 HWND hNotify;
16 HFONT hFont;
17 SIZE ClientSize;
18 DWORD UIState;
19 union
20 {
21 DWORD dwInternalFlags;
22 struct
23 {
24 UINT Enabled : 1;
25 UINT HasFocus : 1;
26 UINT CanDisplay : 1;
27 UINT LeftBtnDown : 1;
28 UINT IsDraggingMonitor : 1;
29 };
30 };
31 DWORD ControlExStyle;
32 DWORD MonitorsCount;
33 INT SelectedMonitor;
34 INT DraggingMonitor;
35 RECT rcDragging;
36 POINT ptDrag, ptDragBegin;
37 SIZE DraggingMargin;
38 PMONSL_MONINFO MonitorInfo;
39 PMONSL_MON Monitors;
40 RECT rcExtent;
41 RECT rcMonitors;
42 RECT rcOldMonitors;
43 POINT ScrollPos;
44 SIZE Margin;
45 SIZE SelectionFrame;
46 HBITMAP hbmDisabledPattern;
47 HBRUSH hbrDisabled;
48 } MONITORSELWND, *PMONITORSELWND;
49
50 static LRESULT
51 MonSelNotify(IN PMONITORSELWND infoPtr,
52 IN UINT code,
53 IN OUT PVOID data)
54 {
55 LRESULT Ret = 0;
56
57 if (infoPtr->hNotify != NULL)
58 {
59 LPNMHDR pnmh = (LPNMHDR)data;
60
61 pnmh->hwndFrom = infoPtr->hSelf;
62 pnmh->idFrom = GetWindowLongPtr(infoPtr->hSelf,
63 GWLP_ID);
64 pnmh->code = code;
65
66 Ret = SendMessage(infoPtr->hNotify,
67 WM_NOTIFY,
68 (WPARAM)pnmh->idFrom,
69 (LPARAM)pnmh);
70 }
71
72 return Ret;
73 }
74
75 static LRESULT
76 MonSelNotifyMonitor(IN PMONITORSELWND infoPtr,
77 IN UINT code,
78 IN INT Index,
79 IN OUT PMONSL_MONNMHDR pmonnmh)
80 {
81 pmonnmh->Index = Index;
82
83 if (Index >= 0)
84 {
85 pmonnmh->MonitorInfo = infoPtr->MonitorInfo[Index];
86 }
87 else
88 {
89 ZeroMemory(&pmonnmh->MonitorInfo,
90 sizeof(pmonnmh->MonitorInfo));
91 }
92
93 return MonSelNotify(infoPtr,
94 code,
95 pmonnmh);
96 }
97
98 static HFONT
99 MonSelChangeFont(IN OUT PMONITORSELWND infoPtr,
100 IN HFONT hFont,
101 IN BOOL Redraw)
102 {
103 HFONT hOldFont = infoPtr->hFont;
104 infoPtr->hFont = hFont;
105
106 if (Redraw)
107 {
108 InvalidateRect(infoPtr->hSelf,
109 NULL,
110 TRUE);
111 }
112
113 return hOldFont;
114 }
115
116 static VOID
117 MonSelRectToScreen(IN PMONITORSELWND infoPtr,
118 IN const RECT *prc,
119 OUT PRECT prcOnScreen)
120 {
121 *prcOnScreen = *prc;
122 OffsetRect(prcOnScreen,
123 -infoPtr->ScrollPos.x,
124 -infoPtr->ScrollPos.y);
125 }
126
127 static VOID
128 MonSelScreenToPt(IN PMONITORSELWND infoPtr,
129 IN const POINT *pptOnScreen,
130 OUT PPOINT ppt)
131 {
132 ppt->x = pptOnScreen->x + infoPtr->ScrollPos.x;
133 ppt->y = pptOnScreen->y + infoPtr->ScrollPos.y;
134 }
135
136 static VOID
137 MonSelMonInfoToRect(IN const MONSL_MONINFO *pMonInfo,
138 OUT PRECT prc)
139 {
140 prc->left = pMonInfo->Position.x;
141 prc->top = pMonInfo->Position.y;
142 prc->right = pMonInfo->Position.x + pMonInfo->Size.cx;
143 prc->bottom = pMonInfo->Position.y + pMonInfo->Size.cy;
144 }
145
146 static INT
147 MonSelHitTest(IN PMONITORSELWND infoPtr,
148 IN const POINT *ppt)
149 {
150 POINT pt;
151 INT Index, Ret = -1;
152
153 if (infoPtr->CanDisplay)
154 {
155 MonSelScreenToPt(infoPtr,
156 ppt,
157 &pt);
158
159 for (Index = 0; Index < (INT)infoPtr->MonitorsCount; Index++)
160 {
161 if (PtInRect(&infoPtr->Monitors[Index].rc,
162 pt))
163 {
164 Ret = Index;
165 break;
166 }
167 }
168 }
169
170 return Ret;
171 }
172
173 static VOID
174 MonSelUpdateExtent(IN OUT PMONITORSELWND infoPtr)
175 {
176 DWORD Index;
177 RECT rcMonitor;
178
179 /* NOTE: This routine calculates the extent of all monitor coordinates.
180 These are not control coordinates! */
181 if (infoPtr->MonitorsCount > 0)
182 {
183 MonSelMonInfoToRect(&infoPtr->MonitorInfo[0],
184 &infoPtr->rcExtent);
185
186 for (Index = 1; Index < infoPtr->MonitorsCount; Index++)
187 {
188 MonSelMonInfoToRect(&infoPtr->MonitorInfo[Index],
189 &rcMonitor);
190
191 UnionRect(&infoPtr->rcExtent,
192 &infoPtr->rcExtent,
193 &rcMonitor);
194 }
195 }
196 else
197 {
198 ZeroMemory(&infoPtr->rcExtent,
199 sizeof(infoPtr->rcExtent));
200 }
201 }
202
203 static VOID
204 MonSelScaleRectRelative(IN const RECT *prcBaseFrom,
205 IN const RECT *prcFrom,
206 IN const RECT *prcBaseTo,
207 OUT PRECT prcTo)
208 {
209 SIZE BaseFrom, BaseTo, From;
210
211 BaseFrom.cx = prcBaseFrom->right - prcBaseFrom->left;
212 BaseFrom.cy = prcBaseFrom->bottom - prcBaseFrom->top;
213 BaseTo.cx = prcBaseTo->right - prcBaseTo->left;
214 BaseTo.cy = prcBaseTo->bottom - prcBaseTo->top;
215 From.cx = prcFrom->right - prcFrom->left;
216 From.cy = prcFrom->bottom - prcFrom->top;
217
218 prcTo->left = prcBaseTo->left + (((prcFrom->left - prcBaseFrom->left) * BaseTo.cx) / BaseFrom.cx);
219 prcTo->top = prcBaseTo->top + (((prcFrom->top - prcBaseFrom->top) * BaseTo.cy) / BaseFrom.cy);
220 prcTo->right = prcTo->left + ((From.cx * BaseTo.cx) / BaseFrom.cx);
221 prcTo->bottom = prcTo->top + ((From.cy * BaseTo.cy) / BaseFrom.cy);
222 }
223
224 static VOID
225 ScaleRectSizeFit(IN const RECT *prcContainerRect,
226 IN OUT PRECT prcRectToScale)
227 {
228 SIZE ContainerSize, RectSize;
229
230 ContainerSize.cx = prcContainerRect->right - prcContainerRect->left;
231 ContainerSize.cy = prcContainerRect->bottom - prcContainerRect->top;
232 RectSize.cx = prcRectToScale->right - prcRectToScale->left;
233 RectSize.cy = prcRectToScale->bottom - prcRectToScale->top;
234
235 if (((RectSize.cx * 0xFFF) / RectSize.cy) < ((ContainerSize.cx * 0xFFF) / ContainerSize.cy))
236 {
237 RectSize.cx = (RectSize.cx * ((ContainerSize.cy * 0xFFF) / RectSize.cy)) / 0xFFF;
238 RectSize.cy = ContainerSize.cy;
239 }
240 else
241 {
242 RectSize.cy = (RectSize.cy * ((ContainerSize.cx * 0xFFF) / RectSize.cx)) / 0xFFF;
243 RectSize.cx = ContainerSize.cx;
244 }
245
246 prcRectToScale->right = prcRectToScale->left + RectSize.cx;
247 prcRectToScale->bottom = prcRectToScale->top + RectSize.cy;
248
249 OffsetRect(prcRectToScale,
250 prcContainerRect->left + ((ContainerSize.cx - RectSize.cx) / 2),
251 prcContainerRect->top + ((ContainerSize.cy - RectSize.cy) / 2));
252 }
253
254 static VOID
255 MonSelRepaint(IN PMONITORSELWND infoPtr)
256 {
257 RECT rc;
258
259 MonSelRectToScreen(infoPtr,
260 &infoPtr->rcMonitors,
261 &rc);
262 InvalidateRect(infoPtr->hSelf,
263 &rc,
264 TRUE);
265
266 if (!EqualRect(&infoPtr->rcMonitors, &infoPtr->rcOldMonitors) &&
267 infoPtr->rcOldMonitors.right != infoPtr->rcOldMonitors.left)
268 {
269 MonSelRectToScreen(infoPtr, &infoPtr->rcOldMonitors, &rc);
270 InvalidateRect(infoPtr->hSelf, &rc, TRUE);
271 infoPtr->rcOldMonitors = infoPtr->rcMonitors;
272 }
273 }
274
275 static VOID
276 MonSelRepaintMonitor(IN PMONITORSELWND infoPtr,
277 IN DWORD Index)
278 {
279 RECT rc;
280 BOOL NoRepaint = FALSE;
281
282 if (Index < infoPtr->MonitorsCount)
283 {
284 if (Index == (DWORD)infoPtr->DraggingMonitor)
285 {
286 if (infoPtr->IsDraggingMonitor)
287 {
288 MonSelRectToScreen(infoPtr,
289 &infoPtr->rcDragging,
290 &rc);
291 }
292 else
293 NoRepaint = TRUE;
294 }
295 else
296 {
297 MonSelRectToScreen(infoPtr,
298 &infoPtr->Monitors[Index].rc,
299 &rc);
300 }
301
302 if (!NoRepaint)
303 {
304 InvalidateRect(infoPtr->hSelf,
305 &rc,
306 TRUE);
307 }
308 }
309 }
310
311 static VOID
312 MonSelRepaintSelected(IN PMONITORSELWND infoPtr)
313 {
314 if (infoPtr->SelectedMonitor >= 0)
315 {
316 MonSelRepaintMonitor(infoPtr,
317 (DWORD)infoPtr->SelectedMonitor);
318 }
319 }
320
321 static VOID
322 MonSelResetMonitors(IN OUT PMONITORSELWND infoPtr)
323 {
324 DWORD Index;
325
326 for (Index = 0; Index < infoPtr->MonitorsCount; Index++)
327 {
328 if (infoPtr->Monitors[Index].hFont != NULL)
329 {
330 DeleteObject(infoPtr->Monitors[Index].hFont);
331 infoPtr->Monitors[Index].hFont = NULL;
332 }
333 }
334 }
335
336
337 static VOID
338 MonSelUpdateMonitorsInfo(IN OUT PMONITORSELWND infoPtr,
339 IN BOOL bRepaint)
340 {
341 RECT rcExtSurface, rcExtDisplay;
342 DWORD Index;
343
344 /* Recalculate rcExtent */
345 MonSelUpdateExtent(infoPtr);
346
347 infoPtr-> CanDisplay = infoPtr->MonitorsCount != 0 &&
348 (infoPtr->ClientSize.cx > (2 * (infoPtr->Margin.cx + infoPtr->SelectionFrame.cx))) &&
349 (infoPtr->ClientSize.cy > (2 * (infoPtr->Margin.cy + infoPtr->SelectionFrame.cy)));
350
351 if (infoPtr->CanDisplay)
352 {
353 /* Calculate the rectangle on the control in which may be painted */
354 rcExtSurface.left = infoPtr->Margin.cx;
355 rcExtSurface.top = infoPtr->Margin.cy;
356 rcExtSurface.right = rcExtSurface.left + infoPtr->ClientSize.cx - (2 * infoPtr->Margin.cx);
357 rcExtSurface.bottom = rcExtSurface.top + infoPtr->ClientSize.cy - (2 * infoPtr->Margin.cy);
358
359 /* Calculate the rectangle on the control that is actually painted on */
360 rcExtDisplay.left = rcExtDisplay.top = 0;
361 rcExtDisplay.right = infoPtr->rcExtent.right - infoPtr->rcExtent.left;
362 rcExtDisplay.bottom = infoPtr->rcExtent.bottom - infoPtr->rcExtent.top;
363
364 ScaleRectSizeFit(&rcExtSurface,
365 &rcExtDisplay);
366
367 infoPtr->rcOldMonitors = infoPtr->rcMonitors;
368 infoPtr->rcMonitors = rcExtDisplay;
369
370 /* Now that we know in which area all monitors are located,
371 calculate the monitors selection rectangles on the screen */
372
373 for (Index = 0; Index < infoPtr->MonitorsCount; Index++)
374 {
375 MonSelMonInfoToRect(&infoPtr->MonitorInfo[Index],
376 &rcExtDisplay);
377
378 MonSelScaleRectRelative(&infoPtr->rcExtent,
379 &rcExtDisplay,
380 &infoPtr->rcMonitors,
381 &infoPtr->Monitors[Index].rc);
382 }
383
384 MonSelResetMonitors(infoPtr);
385
386 if (bRepaint)
387 MonSelRepaint(infoPtr);
388 }
389 else if (bRepaint)
390 {
391 InvalidateRect(infoPtr->hSelf,
392 NULL,
393 TRUE);
394 }
395 }
396
397 static BOOL
398 MonSelSetMonitorsInfo(IN OUT PMONITORSELWND infoPtr,
399 IN DWORD dwMonitors,
400 IN const MONSL_MONINFO *MonitorsInfo)
401 {
402 DWORD Index;
403 BOOL Ret = TRUE;
404
405 if (infoPtr->DraggingMonitor >= 0)
406 return FALSE;
407
408 if (infoPtr->MonitorInfo != NULL)
409 {
410 LocalFree((HLOCAL)infoPtr->MonitorInfo);
411 infoPtr->MonitorInfo = NULL;
412
413 MonSelResetMonitors(infoPtr);
414
415 LocalFree((HLOCAL)infoPtr->Monitors);
416 infoPtr->Monitors = NULL;
417
418 infoPtr->MonitorsCount = 0;
419 }
420
421 if (dwMonitors != 0)
422 {
423 infoPtr->MonitorInfo = (PMONSL_MONINFO)LocalAlloc(LMEM_FIXED,
424 dwMonitors * sizeof(MONSL_MONINFO));
425 if (infoPtr->MonitorInfo != NULL)
426 {
427 infoPtr->Monitors = (PMONSL_MON)LocalAlloc(LMEM_FIXED,
428 dwMonitors * sizeof(MONSL_MON));
429 if (infoPtr->Monitors != NULL)
430 {
431 CopyMemory(infoPtr->MonitorInfo,
432 MonitorsInfo,
433 dwMonitors * sizeof(MONSL_MONINFO));
434 ZeroMemory(infoPtr->Monitors,
435 dwMonitors * sizeof(MONSL_MON));
436
437 for (Index = 0; Index < dwMonitors; Index++)
438 {
439 _stprintf(infoPtr->Monitors[Index].szCaption,
440 _T("%u"),
441 Index + 1);
442 }
443
444 infoPtr->MonitorsCount = dwMonitors;
445
446 if (infoPtr->SelectedMonitor >= (INT)infoPtr->MonitorsCount)
447 infoPtr->SelectedMonitor = -1;
448
449 if (!(infoPtr->ControlExStyle & MSLM_EX_ALLOWSELECTNONE) && infoPtr->SelectedMonitor < 0)
450 infoPtr->SelectedMonitor = 0;
451
452 MonSelUpdateMonitorsInfo(infoPtr,
453 TRUE);
454 }
455 else
456 {
457 LocalFree((HLOCAL)infoPtr->MonitorInfo);
458 infoPtr->MonitorInfo = NULL;
459
460 Ret = FALSE;
461 }
462 }
463 else
464 Ret = FALSE;
465 }
466
467 if (!Ret)
468 infoPtr->SelectedMonitor = -1;
469
470 if (!Ret || dwMonitors == 0)
471 {
472 InvalidateRect(infoPtr->hSelf,
473 NULL,
474 TRUE);
475 }
476
477 return Ret;
478 }
479
480 static DWORD
481 MonSelGetMonitorsInfo(IN PMONITORSELWND infoPtr,
482 IN DWORD dwMonitors,
483 IN OUT PMONSL_MONINFO MonitorsInfo)
484 {
485 if (dwMonitors != 0)
486 {
487 if (dwMonitors > infoPtr->MonitorsCount)
488 dwMonitors = infoPtr->MonitorsCount;
489
490 CopyMemory(MonitorsInfo,
491 infoPtr->MonitorInfo,
492 dwMonitors * sizeof(MONSL_MONINFO));
493 return dwMonitors;
494 }
495 else
496 return infoPtr->MonitorsCount;
497 }
498
499 static BOOL
500 MonSelSetMonitorInfo(IN OUT PMONITORSELWND infoPtr,
501 IN INT Index,
502 IN const MONSL_MONINFO *MonitorsInfo)
503 {
504 if (infoPtr->DraggingMonitor < 0 &&
505 Index >= 0 && Index < (INT)infoPtr->MonitorsCount)
506 {
507 CopyMemory(&infoPtr->MonitorInfo[Index],
508 MonitorsInfo,
509 sizeof(MONSL_MONINFO));
510
511 MonSelUpdateMonitorsInfo(infoPtr,
512 TRUE);
513 return TRUE;
514 }
515
516 return FALSE;
517 }
518
519 static BOOL
520 MonSelGetMonitorInfo(IN PMONITORSELWND infoPtr,
521 IN INT Index,
522 IN OUT PMONSL_MONINFO MonitorsInfo)
523 {
524 if (Index >= 0 && Index < (INT)infoPtr->MonitorsCount)
525 {
526 CopyMemory(MonitorsInfo,
527 &infoPtr->MonitorInfo[Index],
528 sizeof(MONSL_MONINFO));
529 return TRUE;
530 }
531
532 return FALSE;
533 }
534
535 static INT
536 MonSelGetMonitorRect(IN OUT PMONITORSELWND infoPtr,
537 IN INT Index,
538 OUT PRECT prc)
539 {
540 RECT rc, rcClient;
541
542 if (Index < 0 || (UINT)Index >= infoPtr->MonitorsCount)
543 return -1;
544
545 if (!infoPtr->CanDisplay)
546 return 0;
547
548 MonSelRectToScreen(infoPtr,
549 &infoPtr->Monitors[Index].rc,
550 prc);
551
552 rcClient.left = rcClient.top = 0;
553 rcClient.right = infoPtr->ClientSize.cx;
554 rcClient.bottom = infoPtr->ClientSize.cy;
555
556 return IntersectRect(&rc,
557 &rcClient,
558 prc) != FALSE;
559 }
560
561 static BOOL
562 MonSelSetCurSelMonitor(IN OUT PMONITORSELWND infoPtr,
563 IN INT Index,
564 IN BOOL bNotify)
565 {
566 INT PrevSel;
567 BOOL PreventSelect = FALSE;
568 BOOL Ret = FALSE;
569
570 if (infoPtr->DraggingMonitor < 0 &&
571 (Index == -1 || Index < (INT)infoPtr->MonitorsCount))
572 {
573 if (Index != infoPtr->SelectedMonitor)
574 {
575 if ((infoPtr->MonitorInfo[Index].Flags & MSL_MIF_DISABLED) &&
576 !(infoPtr->ControlExStyle & MSLM_EX_ALLOWSELECTDISABLED))
577 {
578 PreventSelect = TRUE;
579 }
580
581 if (!PreventSelect && bNotify)
582 {
583 MONSL_MONNMMONITORCHANGING nmi;
584
585 nmi.PreviousSelected = infoPtr->SelectedMonitor;
586 nmi.AllowChanging = TRUE;
587
588 MonSelNotifyMonitor(infoPtr,
589 MSLN_MONITORCHANGING,
590 Index,
591 &nmi.hdr);
592
593 PreventSelect = (nmi.AllowChanging == FALSE);
594 }
595
596 if (!PreventSelect)
597 {
598 PrevSel = infoPtr->SelectedMonitor;
599 infoPtr->SelectedMonitor = Index;
600
601 if (PrevSel >= 0)
602 {
603 MonSelRepaintMonitor(infoPtr,
604 PrevSel);
605 }
606
607 if (infoPtr->SelectedMonitor >= 0)
608 MonSelRepaintSelected(infoPtr);
609
610 if (bNotify)
611 {
612 MONSL_MONNMHDR nm;
613
614 MonSelNotifyMonitor(infoPtr,
615 MSLN_MONITORCHANGED,
616 Index,
617 &nm);
618 }
619 }
620 }
621
622 Ret = TRUE;
623 }
624
625 return Ret;
626 }
627
628 static VOID
629 MonSelCreate(IN OUT PMONITORSELWND infoPtr)
630 {
631 infoPtr->SelectionFrame.cx = infoPtr->SelectionFrame.cy = 4;
632 infoPtr->Margin.cx = infoPtr->Margin.cy = 20;
633 infoPtr->SelectedMonitor = -1;
634 infoPtr->DraggingMonitor = -1;
635 infoPtr->ControlExStyle = MSLM_EX_ALLOWSELECTDISABLED | MSLM_EX_HIDENUMBERONSINGLE |
636 MSLM_EX_SELECTONRIGHTCLICK | MSLM_EX_SELECTBYARROWKEY;
637 return;
638 }
639
640 static VOID
641 MonSelDestroy(IN OUT PMONITORSELWND infoPtr)
642 {
643 /* Free all monitors */
644 MonSelSetMonitorsInfo(infoPtr,
645 0,
646 NULL);
647
648 if (infoPtr->hbrDisabled != NULL)
649 {
650 DeleteObject(infoPtr->hbrDisabled);
651 infoPtr->hbrDisabled = NULL;
652 }
653
654 if (infoPtr->hbmDisabledPattern != NULL)
655 {
656 DeleteObject(infoPtr->hbmDisabledPattern);
657 infoPtr->hbmDisabledPattern = NULL;
658 }
659 }
660
661 static BOOL
662 MonSelSetExtendedStyle(IN OUT PMONITORSELWND infoPtr,
663 IN DWORD dwExtendedStyle)
664 {
665 if (infoPtr->DraggingMonitor >= 0)
666 return FALSE;
667
668 if (dwExtendedStyle != infoPtr->ControlExStyle)
669 {
670 infoPtr->ControlExStyle = dwExtendedStyle;
671
672 /* Repaint the control */
673 InvalidateRect(infoPtr->hSelf,
674 NULL,
675 TRUE);
676 }
677
678 return TRUE;
679 }
680
681 static DWORD
682 MonSelGetExtendedStyle(IN PMONITORSELWND infoPtr)
683 {
684 return infoPtr->ControlExStyle;
685 }
686
687 static HFONT
688 MonSelGetMonitorFont(IN OUT PMONITORSELWND infoPtr,
689 IN HDC hDC,
690 IN INT Index)
691 {
692 TEXTMETRIC tm;
693 SIZE rcsize;
694 LOGFONT lf;
695 HFONT hPrevFont, hFont;
696 //INT len;
697
698 hFont = infoPtr->Monitors[Index].hFont;
699 if (hFont == NULL &&
700 GetObject(infoPtr->hFont,
701 sizeof(lf),
702 &lf) != 0)
703 {
704 rcsize.cx = infoPtr->Monitors[Index].rc.right - infoPtr->Monitors[Index].rc.left -
705 (2 * infoPtr->SelectionFrame.cx) - 2;
706 rcsize.cy = infoPtr->Monitors[Index].rc.bottom - infoPtr->Monitors[Index].rc.top -
707 (2 * infoPtr->SelectionFrame.cy) - 2;
708 rcsize.cy = (rcsize.cy * 60) / 100;
709
710 //len = _tcslen(infoPtr->Monitors[Index].szCaption);
711
712 hPrevFont = SelectObject(hDC,
713 infoPtr->hFont);
714
715 if (GetTextMetrics(hDC,
716 &tm))
717 {
718 lf.lfWeight = FW_SEMIBOLD;
719 lf.lfHeight = -MulDiv(rcsize.cy - tm.tmExternalLeading,
720 GetDeviceCaps(hDC,
721 LOGPIXELSY),
722 72);
723
724 hFont = CreateFontIndirect(&lf);
725 if (hFont != NULL)
726 infoPtr->Monitors[Index].hFont = hFont;
727 }
728
729 SelectObject(hDC,
730 hPrevFont);
731 }
732
733 return hFont;
734 }
735
736 static BOOL
737 MonSelDrawDisabledRect(IN OUT PMONITORSELWND infoPtr,
738 IN HDC hDC,
739 IN const RECT *prc)
740 {
741 BOOL Ret = FALSE;
742
743 if (infoPtr->hbrDisabled == NULL)
744 {
745 static const DWORD Pattern[4] = {0x5555AAAA, 0x5555AAAA, 0x5555AAAA, 0x5555AAAA};
746
747 if (infoPtr->hbmDisabledPattern == NULL)
748 {
749 infoPtr->hbmDisabledPattern = CreateBitmap(8,
750 8,
751 1,
752 1,
753 Pattern);
754 }
755
756 if (infoPtr->hbmDisabledPattern != NULL)
757 infoPtr->hbrDisabled = CreatePatternBrush(infoPtr->hbmDisabledPattern);
758 }
759
760 if (infoPtr->hbrDisabled != NULL)
761 {
762 /* FIXME: Implement */
763 }
764
765 return Ret;
766 }
767
768 static VOID
769 MonSelPaintMonitor(IN OUT PMONITORSELWND infoPtr,
770 IN HDC hDC,
771 IN DWORD Index,
772 IN OUT PRECT prc,
773 IN COLORREF crDefFontColor,
774 IN BOOL bHideNumber)
775 {
776 HFONT hFont, hPrevFont;
777 COLORREF crPrevText;
778
779 if ((INT)Index == infoPtr->SelectedMonitor)
780 {
781 FillRect(hDC,
782 prc,
783 (HBRUSH)(COLOR_HIGHLIGHT + 1));
784
785 if (infoPtr->HasFocus && !(infoPtr->UIState & UISF_HIDEFOCUS))
786 {
787 /* NOTE: We need to switch the text color to the default, because
788 DrawFocusRect draws a solid line if the text is white! */
789
790 crPrevText = SetTextColor(hDC,
791 crDefFontColor);
792
793 DrawFocusRect(hDC,
794 prc);
795
796 SetTextColor(hDC,
797 crPrevText);
798 }
799 }
800
801 InflateRect(prc,
802 -infoPtr->SelectionFrame.cx,
803 -infoPtr->SelectionFrame.cy);
804
805 Rectangle(hDC,
806 prc->left,
807 prc->top,
808 prc->right,
809 prc->bottom);
810
811 InflateRect(prc,
812 -1,
813 -1);
814
815 if (!bHideNumber)
816 {
817 hFont = MonSelGetMonitorFont(infoPtr,
818 hDC,
819 Index);
820 if (hFont != NULL)
821 {
822 hPrevFont = SelectObject(hDC,
823 hFont);
824
825 DrawText(hDC,
826 infoPtr->Monitors[Index].szCaption,
827 -1,
828 prc,
829 DT_VCENTER | DT_CENTER | DT_NOPREFIX | DT_SINGLELINE);
830
831 SelectObject(hDC,
832 hPrevFont);
833 }
834 }
835
836 if (infoPtr->MonitorInfo[Index].Flags & MSL_MIF_DISABLED)
837 {
838 InflateRect(prc,
839 1,
840 1);
841
842 MonSelDrawDisabledRect(infoPtr,
843 hDC,
844 prc);
845 }
846 }
847
848 static VOID
849 MonSelPaint(IN OUT PMONITORSELWND infoPtr,
850 IN HDC hDC,
851 IN const RECT *prcUpdate)
852 {
853 COLORREF crPrevText;
854 HBRUSH hbBk, hbOldBk;
855 HPEN hpFg, hpOldFg;
856 DWORD Index;
857 RECT rc, rctmp;
858 INT iPrevBkMode;
859 BOOL bHideNumber;
860
861 bHideNumber = (infoPtr->ControlExStyle & MSLM_EX_HIDENUMBERS) ||
862 ((infoPtr->MonitorsCount == 1) && (infoPtr->ControlExStyle & MSLM_EX_HIDENUMBERONSINGLE));
863
864 hbBk = GetSysColorBrush(COLOR_BACKGROUND);
865 hpFg = CreatePen(PS_SOLID,
866 0,
867 GetSysColor(COLOR_HIGHLIGHTTEXT));
868
869 hbOldBk = SelectObject(hDC,
870 hbBk);
871 hpOldFg = SelectObject(hDC,
872 hpFg);
873 iPrevBkMode = SetBkMode(hDC,
874 TRANSPARENT);
875 crPrevText = SetTextColor(hDC,
876 GetSysColor(COLOR_HIGHLIGHTTEXT));
877
878 for (Index = 0; Index < infoPtr->MonitorsCount; Index++)
879 {
880 if (infoPtr->IsDraggingMonitor &&
881 (DWORD)infoPtr->DraggingMonitor == Index)
882 {
883 continue;
884 }
885
886 MonSelRectToScreen(infoPtr,
887 &infoPtr->Monitors[Index].rc,
888 &rc);
889
890 if (IntersectRect(&rctmp,
891 &rc,
892 prcUpdate))
893 {
894 MonSelPaintMonitor(infoPtr,
895 hDC,
896 Index,
897 &rc,
898 crPrevText,
899 bHideNumber);
900 }
901 }
902
903 /* Paint the dragging monitor last */
904 if (infoPtr->IsDraggingMonitor &&
905 infoPtr->DraggingMonitor >= 0)
906 {
907 MonSelRectToScreen(infoPtr,
908 &infoPtr->rcDragging,
909 &rc);
910
911 if (IntersectRect(&rctmp,
912 &rc,
913 prcUpdate))
914 {
915 MonSelPaintMonitor(infoPtr,
916 hDC,
917 (DWORD)infoPtr->DraggingMonitor,
918 &rc,
919 crPrevText,
920 bHideNumber);
921 }
922 }
923
924 SetTextColor(hDC,
925 crPrevText);
926 SetBkMode(hDC,
927 iPrevBkMode);
928 SelectObject(hDC,
929 hpOldFg);
930 SelectObject(hDC,
931 hbOldBk);
932
933 DeleteObject(hpFg);
934 }
935
936 static VOID
937 MonSelContextMenu(IN OUT PMONITORSELWND infoPtr,
938 IN SHORT x,
939 IN SHORT y)
940 {
941 MONSL_MONNMBUTTONCLICKED nm;
942 INT Index;
943
944 if (!infoPtr->HasFocus)
945 SetFocus(infoPtr->hSelf);
946
947 nm.pt.x = x;
948 nm.pt.y = y;
949
950 Index = MonSelHitTest(infoPtr,
951 &nm.pt);
952
953 MonSelNotifyMonitor(infoPtr,
954 MSLN_RBUTTONUP,
955 Index,
956 (PMONSL_MONNMHDR)&nm);
957
958 /* Send a WM_CONTEXTMENU notification */
959 MapWindowPoints(infoPtr->hSelf,
960 NULL,
961 &nm.pt,
962 1);
963
964 SendMessage(infoPtr->hSelf,
965 WM_CONTEXTMENU,
966 (WPARAM)infoPtr->hSelf,
967 MAKELPARAM(nm.pt.x,
968 nm.pt.y));
969 }
970
971 static VOID
972 MonSelApplyCursorClipping(IN PMONITORSELWND infoPtr,
973 IN BOOL bClip)
974 {
975 RECT rc;
976
977 if (bClip)
978 {
979 rc.left = rc.top = 0;
980 rc.right = infoPtr->ClientSize.cx;
981 rc.bottom = infoPtr->ClientSize.cy;
982
983 if (MapWindowPoints(infoPtr->hSelf,
984 NULL,
985 (LPPOINT)&rc,
986 2))
987 {
988 ClipCursor(&rc);
989 }
990 }
991 else
992 {
993 ClipCursor(NULL);
994 }
995 }
996
997 static VOID
998 MonSelMoveDragRect(IN OUT PMONITORSELWND infoPtr,
999 IN PPOINT ppt)
1000 {
1001 RECT rcPrev, rcUpdate, *prc;
1002 HRGN hRgnPrev;
1003 HDC hDC;
1004
1005 if (infoPtr->CanDisplay)
1006 {
1007 hDC = GetDC(infoPtr->hSelf);
1008 if (hDC != NULL)
1009 {
1010 if (infoPtr->ptDrag.x != ppt->x ||
1011 infoPtr->ptDrag.y != ppt->y)
1012 {
1013 infoPtr->ptDrag = *ppt;
1014
1015 rcPrev = infoPtr->rcDragging;
1016
1017 /* Calculate updated dragging rectangle */
1018 prc = &infoPtr->Monitors[infoPtr->DraggingMonitor].rc;
1019 infoPtr->rcDragging.left = ppt->x - infoPtr->DraggingMargin.cx;
1020 infoPtr->rcDragging.top = ppt->y - infoPtr->DraggingMargin.cy;
1021 infoPtr->rcDragging.right = infoPtr->rcDragging.left + (prc->right - prc->left);
1022 infoPtr->rcDragging.bottom = infoPtr->rcDragging.top + (prc->bottom - prc->top);
1023
1024 hRgnPrev = CreateRectRgn(rcPrev.left,
1025 rcPrev.top,
1026 rcPrev.right,
1027 rcPrev.bottom);
1028
1029 if (hRgnPrev != NULL)
1030 {
1031 if (!ScrollDC(hDC,
1032 infoPtr->rcDragging.left - rcPrev.left,
1033 infoPtr->rcDragging.top - rcPrev.top,
1034 &rcPrev,
1035 NULL,
1036 hRgnPrev,
1037 &rcUpdate) ||
1038 !InvalidateRgn(infoPtr->hSelf,
1039 hRgnPrev,
1040 TRUE))
1041 {
1042 DeleteObject(hRgnPrev);
1043 goto InvRects;
1044 }
1045
1046 DeleteObject(hRgnPrev);
1047 }
1048 else
1049 {
1050 InvRects:
1051 InvalidateRect(infoPtr->hSelf,
1052 &rcPrev,
1053 TRUE);
1054 InvalidateRect(infoPtr->hSelf,
1055 &infoPtr->rcDragging,
1056 TRUE);
1057 }
1058 }
1059
1060 ReleaseDC(infoPtr->hSelf,
1061 hDC);
1062 }
1063 }
1064 }
1065
1066 static VOID
1067 MonSelCancelDragging(IN OUT PMONITORSELWND infoPtr)
1068 {
1069 DWORD Index;
1070
1071 if (infoPtr->DraggingMonitor >= 0)
1072 {
1073 MonSelMoveDragRect(infoPtr,
1074 &infoPtr->ptDragBegin);
1075
1076 Index = (DWORD)infoPtr->DraggingMonitor;
1077 infoPtr->DraggingMonitor = -1;
1078
1079 if (infoPtr->CanDisplay)
1080 {
1081 /* Repaint the area where the monitor was last dragged */
1082 MonSelRepaintMonitor(infoPtr,
1083 Index);
1084
1085 infoPtr->IsDraggingMonitor = FALSE;
1086
1087 /* Repaint the area where the monitor is located */
1088 MonSelRepaintMonitor(infoPtr,
1089 Index);
1090 }
1091 else
1092 infoPtr->IsDraggingMonitor = FALSE;
1093
1094 ReleaseCapture();
1095
1096 MonSelApplyCursorClipping(infoPtr,
1097 FALSE);
1098 }
1099 }
1100
1101 static VOID
1102 MonSelInitDragging(IN OUT PMONITORSELWND infoPtr,
1103 IN DWORD Index,
1104 IN PPOINT ppt)
1105 {
1106 POINT pt;
1107
1108 MonSelCancelDragging(infoPtr);
1109 infoPtr->IsDraggingMonitor = FALSE;
1110
1111 MonSelScreenToPt(infoPtr,
1112 ppt,
1113 &pt);
1114
1115 infoPtr->ptDrag = infoPtr->ptDragBegin = pt;
1116 infoPtr->DraggingMonitor = (INT)Index;
1117
1118 infoPtr->DraggingMargin.cx = ppt->x - infoPtr->Monitors[Index].rc.left;
1119 infoPtr->DraggingMargin.cy = ppt->y - infoPtr->Monitors[Index].rc.top;
1120 infoPtr->rcDragging = infoPtr->Monitors[Index].rc;
1121
1122 MonSelApplyCursorClipping(infoPtr,
1123 TRUE);
1124 }
1125
1126 static VOID
1127 MonSelDrag(IN OUT PMONITORSELWND infoPtr,
1128 IN PPOINT ppt)
1129 {
1130 SIZE szDrag;
1131 POINT pt;
1132 RECT rcDrag;
1133
1134 if (infoPtr->DraggingMonitor >= 0)
1135 {
1136 MonSelScreenToPt(infoPtr,
1137 ppt,
1138 &pt);
1139
1140 if (!infoPtr->IsDraggingMonitor)
1141 {
1142 szDrag.cx = GetSystemMetrics(SM_CXDRAG);
1143 szDrag.cy = GetSystemMetrics(SM_CYDRAG);
1144
1145 rcDrag.left = infoPtr->Monitors[infoPtr->DraggingMonitor].rc.left + infoPtr->DraggingMargin.cx - (szDrag.cx / 2);
1146 rcDrag.top = infoPtr->Monitors[infoPtr->DraggingMonitor].rc.top + infoPtr->DraggingMargin.cy - (szDrag.cy / 2);
1147 rcDrag.right = rcDrag.left + szDrag.cx;
1148 rcDrag.bottom = rcDrag.top + szDrag.cy;
1149
1150 if (!PtInRect(&rcDrag,
1151 pt))
1152 {
1153 /* The user started moving around the mouse: Begin dragging */
1154 infoPtr->IsDraggingMonitor = TRUE;
1155 MonSelMoveDragRect(infoPtr,
1156 &pt);
1157 }
1158 }
1159 else
1160 {
1161 MonSelMoveDragRect(infoPtr,
1162 &pt);
1163 }
1164 }
1165 }
1166
1167 static LRESULT CALLBACK
1168 MonitorSelWndProc(IN HWND hwnd,
1169 IN UINT uMsg,
1170 IN WPARAM wParam,
1171 IN LPARAM lParam)
1172 {
1173 PMONITORSELWND infoPtr;
1174 LRESULT Ret = 0;
1175
1176 infoPtr = (PMONITORSELWND)GetWindowLongPtrW(hwnd,
1177 0);
1178
1179 if (infoPtr == NULL && uMsg != WM_CREATE)
1180 {
1181 goto HandleDefaultMessage;
1182 }
1183
1184 switch (uMsg)
1185 {
1186 case WM_PAINT:
1187 case WM_PRINTCLIENT:
1188 {
1189 PAINTSTRUCT ps;
1190 HDC hDC;
1191
1192 if (wParam != 0)
1193 {
1194 if (!GetUpdateRect(hwnd,
1195 &ps.rcPaint,
1196 TRUE))
1197 {
1198 break;
1199 }
1200 hDC = (HDC)wParam;
1201 }
1202 else
1203 {
1204 hDC = BeginPaint(hwnd,
1205 &ps);
1206 if (hDC == NULL)
1207 {
1208 break;
1209 }
1210 }
1211
1212 if (infoPtr->CanDisplay)
1213 {
1214 MonSelPaint(infoPtr,
1215 hDC,
1216 &ps.rcPaint);
1217 }
1218
1219 if (wParam == 0)
1220 {
1221 EndPaint(hwnd,
1222 &ps);
1223 }
1224 break;
1225 }
1226
1227 case WM_MOUSEMOVE:
1228 {
1229 POINT pt;
1230
1231 if (!(wParam & MK_LBUTTON))
1232 {
1233 MonSelCancelDragging(infoPtr);
1234 break;
1235 }
1236
1237 if (infoPtr->LeftBtnDown)
1238 {
1239 pt.x = (LONG)LOWORD(lParam);
1240 pt.y = (LONG)HIWORD(lParam);
1241
1242 MonSelDrag(infoPtr,
1243 &pt);
1244 }
1245
1246 break;
1247 }
1248
1249 case WM_RBUTTONDOWN:
1250 {
1251 if (!(infoPtr->ControlExStyle & MSLM_EX_SELECTONRIGHTCLICK))
1252 break;
1253
1254 /* Fall through */
1255 }
1256
1257 case WM_LBUTTONDBLCLK:
1258 case WM_LBUTTONDOWN:
1259 {
1260 INT Index;
1261 POINT pt;
1262
1263 if (!infoPtr->HasFocus)
1264 SetFocus(infoPtr->hSelf);
1265
1266 pt.x = (LONG)LOWORD(lParam);
1267 pt.y = (LONG)HIWORD(lParam);
1268
1269 Index = MonSelHitTest(infoPtr,
1270 &pt);
1271 if (Index >= 0 || (infoPtr->ControlExStyle & MSLM_EX_ALLOWSELECTNONE))
1272 {
1273 MonSelSetCurSelMonitor(infoPtr,
1274 Index,
1275 TRUE);
1276 }
1277
1278 if (Index >= 0 && (uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONDBLCLK))
1279 {
1280 infoPtr->LeftBtnDown = TRUE;
1281 MonSelInitDragging(infoPtr,
1282 (DWORD)Index,
1283 &pt);
1284 }
1285
1286 /* Fall through */
1287 }
1288
1289 case WM_MBUTTONDOWN:
1290 {
1291 if (!infoPtr->HasFocus)
1292 SetFocus(hwnd);
1293 break;
1294 }
1295
1296 case WM_RBUTTONUP:
1297 {
1298 MonSelContextMenu(infoPtr,
1299 (SHORT)LOWORD(lParam),
1300 (SHORT)HIWORD(lParam));
1301 break;
1302 }
1303
1304 case WM_LBUTTONUP:
1305 {
1306 MonSelCancelDragging(infoPtr);
1307 infoPtr->LeftBtnDown = FALSE;
1308 break;
1309 }
1310
1311 case WM_GETDLGCODE:
1312 {
1313 INT virtKey;
1314
1315 virtKey = (lParam != 0 ? (INT)((LPMSG)lParam)->wParam : 0);
1316 switch (virtKey)
1317 {
1318 case VK_TAB:
1319 {
1320 /* Change the UI status */
1321 SendMessage(GetAncestor(hwnd,
1322 GA_PARENT),
1323 WM_CHANGEUISTATE,
1324 MAKEWPARAM(UIS_INITIALIZE,
1325 0),
1326 0);
1327 break;
1328 }
1329 }
1330
1331 Ret |= DLGC_WANTARROWS;
1332
1333 if (infoPtr->ControlExStyle & MSLM_EX_SELECTBYNUMKEY)
1334 Ret |= DLGC_WANTCHARS;
1335 break;
1336 }
1337
1338 case WM_SETFOCUS:
1339 {
1340 infoPtr->HasFocus = TRUE;
1341 MonSelRepaintSelected(infoPtr);
1342 break;
1343 }
1344
1345 case WM_KILLFOCUS:
1346 {
1347 infoPtr->HasFocus = FALSE;
1348 MonSelCancelDragging(infoPtr);
1349 MonSelRepaintSelected(infoPtr);
1350 break;
1351 }
1352
1353 case WM_UPDATEUISTATE:
1354 {
1355 DWORD OldUIState;
1356
1357 Ret = DefWindowProcW(hwnd,
1358 uMsg,
1359 wParam,
1360 lParam);
1361
1362 OldUIState = infoPtr->UIState;
1363 switch (LOWORD(wParam))
1364 {
1365 case UIS_SET:
1366 infoPtr->UIState |= HIWORD(wParam);
1367 break;
1368
1369 case UIS_CLEAR:
1370 infoPtr->UIState &= ~HIWORD(wParam);
1371 break;
1372 }
1373
1374 if (infoPtr->UIState != OldUIState)
1375 MonSelRepaintSelected(infoPtr);
1376 break;
1377 }
1378
1379 case WM_SETFONT:
1380 {
1381 Ret = (LRESULT)MonSelChangeFont(infoPtr,
1382 (HFONT)wParam,
1383 (BOOL)LOWORD(lParam));
1384 break;
1385 }
1386
1387 case WM_SIZE:
1388 {
1389 infoPtr->ClientSize.cx = LOWORD(lParam);
1390 infoPtr->ClientSize.cy = HIWORD(lParam);
1391
1392 /* Don't let MonSelUpdateMonitorsInfo repaint the control
1393 because this won't work properly in case the control
1394 was sized down! */
1395 MonSelUpdateMonitorsInfo(infoPtr,
1396 FALSE);
1397 InvalidateRect(infoPtr->hSelf,
1398 NULL,
1399 TRUE);
1400 break;
1401 }
1402
1403 case WM_GETFONT:
1404 {
1405 Ret = (LRESULT)infoPtr->hFont;
1406 break;
1407 }
1408
1409 case WM_ENABLE:
1410 {
1411 infoPtr->Enabled = ((BOOL)wParam != FALSE);
1412 MonSelRepaint(infoPtr);
1413 break;
1414 }
1415
1416 case WM_STYLECHANGED:
1417 {
1418 if (wParam == GWL_STYLE)
1419 {
1420 unsigned int OldEnabled = infoPtr->Enabled;
1421 infoPtr->Enabled = !(((LPSTYLESTRUCT)lParam)->styleNew & WS_DISABLED);
1422
1423 if (OldEnabled != infoPtr->Enabled)
1424 MonSelRepaint(infoPtr);
1425 }
1426 break;
1427 }
1428
1429 case WM_KEYDOWN:
1430 {
1431 INT Index;
1432
1433 if (infoPtr->ControlExStyle & MSLM_EX_SELECTBYARROWKEY)
1434 {
1435 switch (wParam)
1436 {
1437 case VK_UP:
1438 case VK_LEFT:
1439 {
1440 Index = infoPtr->SelectedMonitor;
1441
1442 if (infoPtr->MonitorsCount != 0)
1443 {
1444 if (Index < 0)
1445 Index = 0;
1446 else if (Index > 0)
1447 Index--;
1448 }
1449
1450 if (Index >= 0)
1451 {
1452 MonSelSetCurSelMonitor(infoPtr,
1453 Index,
1454 TRUE);
1455 }
1456 break;
1457 }
1458
1459 case VK_DOWN:
1460 case VK_RIGHT:
1461 {
1462 Index = infoPtr->SelectedMonitor;
1463
1464 if (infoPtr->MonitorsCount != 0)
1465 {
1466 if (Index < 0)
1467 Index = (INT)infoPtr->MonitorsCount - 1;
1468 else if (Index < (INT)infoPtr->MonitorsCount - 1)
1469 Index++;
1470 }
1471
1472 if (infoPtr->SelectedMonitor < (INT)infoPtr->MonitorsCount)
1473 {
1474 MonSelSetCurSelMonitor(infoPtr,
1475 Index,
1476 TRUE);
1477 }
1478 break;
1479 }
1480 }
1481 }
1482 break;
1483 }
1484
1485 case WM_CHAR:
1486 {
1487 if ((infoPtr->ControlExStyle & MSLM_EX_SELECTBYNUMKEY) &&
1488 wParam >= '1' && wParam <= '9')
1489 {
1490 INT Index = (INT)(wParam - '1');
1491 if (Index < (INT)infoPtr->MonitorsCount)
1492 {
1493 MonSelSetCurSelMonitor(infoPtr,
1494 Index,
1495 TRUE);
1496 }
1497 }
1498 break;
1499 }
1500
1501 case MSLM_SETMONITORSINFO:
1502 {
1503 Ret = MonSelSetMonitorsInfo(infoPtr,
1504 (DWORD)wParam,
1505 (const MONSL_MONINFO *)lParam);
1506 break;
1507 }
1508
1509 case MSLM_GETMONITORSINFO:
1510 {
1511 Ret = MonSelGetMonitorsInfo(infoPtr,
1512 (DWORD)wParam,
1513 (PMONSL_MONINFO)lParam);
1514 break;
1515 }
1516
1517 case MSLM_GETMONITORINFOCOUNT:
1518 {
1519 Ret = infoPtr->MonitorsCount;
1520 break;
1521 }
1522
1523 case MSLM_HITTEST:
1524 {
1525 Ret = MonSelHitTest(infoPtr,
1526 (const POINT *)wParam);
1527 break;
1528 }
1529
1530 case MSLM_SETCURSEL:
1531 {
1532 Ret = MonSelSetCurSelMonitor(infoPtr,
1533 (INT)wParam,
1534 FALSE);
1535 break;
1536 }
1537
1538 case MSLM_GETCURSEL:
1539 {
1540 Ret = infoPtr->SelectedMonitor;
1541 break;
1542 }
1543
1544 case MSLM_SETMONITORINFO:
1545 {
1546 Ret = MonSelSetMonitorInfo(infoPtr,
1547 (INT)wParam,
1548 (const MONSL_MONINFO *)lParam);
1549 break;
1550 }
1551
1552 case MSLM_GETMONITORINFO:
1553 {
1554 Ret = MonSelGetMonitorInfo(infoPtr,
1555 (INT)wParam,
1556 (PMONSL_MONINFO)lParam);
1557 break;
1558 }
1559
1560 case MSLM_SETEXSTYLE:
1561 {
1562 Ret = MonSelSetExtendedStyle(infoPtr,
1563 (DWORD)lParam);
1564 break;
1565 }
1566
1567 case MSLM_GETEXSTYLE:
1568 {
1569 Ret = MonSelGetExtendedStyle(infoPtr);
1570 break;
1571 }
1572
1573 case MSLM_GETMONITORRECT:
1574 {
1575 Ret = (LRESULT)MonSelGetMonitorRect(infoPtr,
1576 (INT)wParam,
1577 (PRECT)lParam);
1578 break;
1579 }
1580
1581 case WM_CREATE:
1582 {
1583 infoPtr = (PMONITORSELWND)HeapAlloc(GetProcessHeap(),
1584 0,
1585 sizeof(MONITORSELWND));
1586 if (infoPtr == NULL)
1587 {
1588 Ret = (LRESULT)-1;
1589 break;
1590 }
1591
1592 ZeroMemory(infoPtr,
1593 sizeof(MONITORSELWND));
1594 infoPtr->hSelf = hwnd;
1595 infoPtr->hNotify = ((LPCREATESTRUCTW)lParam)->hwndParent;
1596 infoPtr->Enabled = !(((LPCREATESTRUCTW)lParam)->style & WS_DISABLED);
1597 infoPtr->UIState = SendMessage(hwnd,
1598 WM_QUERYUISTATE,
1599 0,
1600 0);
1601
1602 SetWindowLongPtrW(hwnd,
1603 0,
1604 (LONG_PTR)infoPtr);
1605
1606 MonSelCreate(infoPtr);
1607 break;
1608 }
1609
1610 case WM_DESTROY:
1611 {
1612 MonSelDestroy(infoPtr);
1613
1614 HeapFree(GetProcessHeap(),
1615 0,
1616 infoPtr);
1617 SetWindowLongPtrW(hwnd,
1618 0,
1619 (DWORD_PTR)NULL);
1620 break;
1621 }
1622
1623 default:
1624 {
1625 HandleDefaultMessage:
1626 Ret = DefWindowProcW(hwnd,
1627 uMsg,
1628 wParam,
1629 lParam);
1630 break;
1631 }
1632 }
1633
1634 return Ret;
1635 }
1636
1637 BOOL
1638 RegisterMonitorSelectionControl(IN HINSTANCE hInstance)
1639 {
1640 WNDCLASS wc = {0};
1641
1642 wc.style = CS_DBLCLKS;
1643 wc.lpfnWndProc = MonitorSelWndProc;
1644 wc.cbWndExtra = sizeof(PMONITORSELWND);
1645 wc.hInstance = hInstance;
1646 wc.hCursor = LoadCursorW(NULL,
1647 (LPWSTR)IDC_ARROW);
1648 wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
1649 wc.lpszClassName = szMonitorSelWndClass;
1650
1651 return RegisterClass(&wc) != 0;
1652 }
1653
1654 VOID
1655 UnregisterMonitorSelectionControl(IN HINSTANCE hInstance)
1656 {
1657 UnregisterClassW(szMonitorSelWndClass,
1658 hInstance);
1659 }