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