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