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