Send notification if another monitor is selected
[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 };
31 };
32 DWORD ControlExStyle;
33 DWORD MonitorsCount;
34 INT SelectedMonitor;
35 PMONSL_MONINFO MonitorInfo;
36 PMONSL_MON Monitors;
37 RECT rcExtent;
38 RECT rcMonitors;
39 POINT ScrollPos;
40 SIZE Margin;
41 SIZE SelectionFrame;
42 HBITMAP hbmDisabledPattern;
43 HBRUSH hbrDisabled;
44 } MONITORSELWND, *PMONITORSELWND;
45
46 static LRESULT
47 MonSelNotify(IN PMONITORSELWND infoPtr,
48 IN UINT code,
49 IN OUT PVOID data)
50 {
51 LRESULT Ret = 0;
52
53 if (infoPtr->hNotify != NULL)
54 {
55 LPNMHDR pnmh = (LPNMHDR)data;
56
57 pnmh->hwndFrom = infoPtr->hSelf;
58 pnmh->idFrom = GetWindowLongPtr(infoPtr->hSelf,
59 GWLP_ID);
60 pnmh->code = code;
61
62 Ret = SendMessage(infoPtr->hNotify,
63 WM_NOTIFY,
64 (WPARAM)pnmh->idFrom,
65 (LPARAM)pnmh);
66 }
67
68 return Ret;
69 }
70
71 static LRESULT
72 MonSelNotifyMonitor(IN PMONITORSELWND infoPtr,
73 IN UINT code,
74 IN INT Index,
75 IN OUT PMONSL_MONNMHDR pmonnmh)
76 {
77 pmonnmh->Index = Index;
78
79 if (Index >= 0)
80 {
81 pmonnmh->MonitorInfo = infoPtr->MonitorInfo[Index];
82 }
83 else
84 {
85 ZeroMemory(&pmonnmh->MonitorInfo,
86 sizeof(pmonnmh->MonitorInfo));
87 }
88
89 return MonSelNotify(infoPtr,
90 code,
91 pmonnmh);
92 }
93
94 static HFONT
95 MonSelChangeFont(IN OUT PMONITORSELWND infoPtr,
96 IN HFONT hFont,
97 IN BOOL Redraw)
98 {
99 HFONT hOldFont = infoPtr->hFont;
100 infoPtr->hFont = hFont;
101
102 if (Redraw)
103 {
104 InvalidateRect(infoPtr->hSelf,
105 NULL,
106 TRUE);
107 }
108
109 return hOldFont;
110 }
111
112 static VOID
113 MonSelRectToScreen(IN PMONITORSELWND infoPtr,
114 IN const RECT *prc,
115 OUT PRECT prcOnScreen)
116 {
117 *prcOnScreen = *prc;
118 OffsetRect(prcOnScreen,
119 -infoPtr->ScrollPos.x,
120 -infoPtr->ScrollPos.y);
121 }
122
123 static VOID
124 MonSelScreenToPt(IN PMONITORSELWND infoPtr,
125 IN const POINT *pptOnScreen,
126 OUT PPOINT ppt)
127 {
128 ppt->x = pptOnScreen->x + infoPtr->ScrollPos.x;
129 ppt->y = pptOnScreen->y + infoPtr->ScrollPos.y;
130 }
131
132 static VOID
133 MonSelMonInfoToRect(IN const MONSL_MONINFO *pMonInfo,
134 OUT PRECT prc)
135 {
136 prc->left = pMonInfo->Position.x;
137 prc->top = pMonInfo->Position.y;
138 prc->right = pMonInfo->Position.x + pMonInfo->Size.cx;
139 prc->bottom = pMonInfo->Position.y + pMonInfo->Size.cy;
140 }
141
142 static INT
143 MonSelHitTest(IN PMONITORSELWND infoPtr,
144 IN const POINT *ppt)
145 {
146 POINT pt;
147 INT Index, Ret = -1;
148
149 if (infoPtr->CanDisplay)
150 {
151 MonSelScreenToPt(infoPtr,
152 ppt,
153 &pt);
154
155 for (Index = 0; Index < (INT)infoPtr->MonitorsCount; Index++)
156 {
157 if (PtInRect(&infoPtr->Monitors[Index].rc,
158 pt))
159 {
160 Ret = Index;
161 break;
162 }
163 }
164 }
165
166 return Ret;
167 }
168
169 static VOID
170 MonSelUpdateExtent(IN OUT PMONITORSELWND infoPtr)
171 {
172 DWORD Index;
173 RECT rcMonitor;
174
175 /* NOTE: This routine calculates the extent of all monitor coordinates.
176 These are not control coordinates! */
177 if (infoPtr->MonitorsCount > 0)
178 {
179 MonSelMonInfoToRect(&infoPtr->MonitorInfo[0],
180 &infoPtr->rcExtent);
181
182 for (Index = 1; Index < infoPtr->MonitorsCount; Index++)
183 {
184 MonSelMonInfoToRect(&infoPtr->MonitorInfo[Index],
185 &rcMonitor);
186
187 UnionRect(&infoPtr->rcExtent,
188 &infoPtr->rcExtent,
189 &rcMonitor);
190 }
191 }
192 else
193 {
194 ZeroMemory(&infoPtr->rcExtent,
195 sizeof(infoPtr->rcExtent));
196 }
197 }
198
199 static VOID
200 MonSelScaleRectRelative(IN const RECT *prcBaseFrom,
201 IN const RECT *prcFrom,
202 IN const RECT *prcBaseTo,
203 OUT PRECT prcTo)
204 {
205 SIZE BaseFrom, BaseTo, From;
206
207 BaseFrom.cx = prcBaseFrom->right - prcBaseFrom->left;
208 BaseFrom.cy = prcBaseFrom->bottom - prcBaseFrom->top;
209 BaseTo.cx = prcBaseTo->right - prcBaseTo->left;
210 BaseTo.cy = prcBaseTo->bottom - prcBaseTo->top;
211 From.cx = prcFrom->right - prcFrom->left;
212 From.cy = prcFrom->bottom - prcFrom->top;
213
214 prcTo->left = prcBaseTo->left + (((prcFrom->left - prcBaseFrom->left) * BaseTo.cx) / BaseFrom.cx);
215 prcTo->top = prcBaseTo->top + (((prcFrom->top - prcBaseFrom->top) * BaseTo.cy) / BaseFrom.cy);
216 prcTo->right = prcTo->left + ((From.cx * BaseTo.cx) / BaseFrom.cx);
217 prcTo->bottom = prcTo->top + ((From.cy * BaseTo.cy) / BaseFrom.cy);
218 }
219
220 static VOID
221 ScaleRectSizeFit(IN const RECT *prcContainerRect,
222 IN OUT PRECT prcRectToScale)
223 {
224 SIZE ContainerSize, RectSize;
225
226 ContainerSize.cx = prcContainerRect->right - prcContainerRect->left;
227 ContainerSize.cy = prcContainerRect->bottom - prcContainerRect->top;
228 RectSize.cx = prcRectToScale->right - prcRectToScale->left;
229 RectSize.cy = prcRectToScale->bottom - prcRectToScale->top;
230
231 if (((RectSize.cx * 0xFFF) / RectSize.cy) < ((ContainerSize.cx * 0xFFF) / ContainerSize.cy))
232 {
233 RectSize.cx = (RectSize.cx * ((ContainerSize.cy * 0xFFF) / RectSize.cy)) / 0xFFF;
234 RectSize.cy = ContainerSize.cy;
235 }
236 else
237 {
238 RectSize.cy = (RectSize.cy * ((ContainerSize.cx * 0xFFF) / RectSize.cx)) / 0xFFF;
239 RectSize.cx = ContainerSize.cx;
240 }
241
242 prcRectToScale->right = prcRectToScale->left + RectSize.cx;
243 prcRectToScale->bottom = prcRectToScale->top + RectSize.cy;
244
245 OffsetRect(prcRectToScale,
246 prcContainerRect->left + ((ContainerSize.cx - RectSize.cx) / 2),
247 prcContainerRect->top + ((ContainerSize.cy - RectSize.cy) / 2));
248 }
249
250 static VOID
251 MonSelRepaint(IN PMONITORSELWND infoPtr)
252 {
253 RECT rc;
254
255 MonSelRectToScreen(infoPtr,
256 &infoPtr->rcMonitors,
257 &rc);
258 InvalidateRect(infoPtr->hSelf,
259 &rc,
260 TRUE);
261 }
262
263 static VOID
264 MonSelRepaintMonitor(IN PMONITORSELWND infoPtr,
265 IN DWORD Index)
266 {
267 RECT rc;
268
269 if (Index < infoPtr->MonitorsCount)
270 {
271 MonSelRectToScreen(infoPtr,
272 &infoPtr->Monitors[Index].rc,
273 &rc);
274 InvalidateRect(infoPtr->hSelf,
275 &rc,
276 TRUE);
277 }
278 }
279
280 static VOID
281 MonSelRepaintSelected(IN PMONITORSELWND infoPtr)
282 {
283 if (infoPtr->SelectedMonitor >= 0)
284 {
285 MonSelRepaintMonitor(infoPtr,
286 (DWORD)infoPtr->SelectedMonitor);
287 }
288 }
289
290 static VOID
291 MonSelResetMonitors(IN OUT PMONITORSELWND infoPtr)
292 {
293 DWORD Index;
294
295 for (Index = 0; Index < infoPtr->MonitorsCount; Index++)
296 {
297 if (infoPtr->Monitors[Index].hFont != NULL)
298 {
299 DeleteObject(infoPtr->Monitors[Index].hFont);
300 infoPtr->Monitors[Index].hFont = NULL;
301 }
302 }
303 }
304
305
306 static VOID
307 MonSelUpdateMonitorsInfo(IN OUT PMONITORSELWND infoPtr,
308 IN BOOL bRepaint)
309 {
310 RECT rcExtSurface, rcExtDisplay;
311 DWORD Index;
312
313 /* Recalculate rcExtent */
314 MonSelUpdateExtent(infoPtr);
315
316 infoPtr-> CanDisplay = infoPtr->MonitorsCount != 0 &&
317 (infoPtr->ClientSize.cx > (2 * (infoPtr->Margin.cx + infoPtr->SelectionFrame.cx))) &&
318 (infoPtr->ClientSize.cy > (2 * (infoPtr->Margin.cy + infoPtr->SelectionFrame.cy)));
319
320 if (infoPtr->CanDisplay)
321 {
322 /* Calculate the rectangle on the control in which may be painted */
323 rcExtSurface.left = infoPtr->Margin.cx;
324 rcExtSurface.top = infoPtr->Margin.cy;
325 rcExtSurface.right = rcExtSurface.left + infoPtr->ClientSize.cx - (2 * infoPtr->Margin.cx);
326 rcExtSurface.bottom = rcExtSurface.top + infoPtr->ClientSize.cy - (2 * infoPtr->Margin.cy);
327
328 /* Calculate the rectangle on the control that is actually painted on */
329 rcExtDisplay.left = rcExtDisplay.top = 0;
330 rcExtDisplay.right = infoPtr->rcExtent.right - infoPtr->rcExtent.left;
331 rcExtDisplay.bottom = infoPtr->rcExtent.bottom - infoPtr->rcExtent.top;
332
333 ScaleRectSizeFit(&rcExtSurface,
334 &rcExtDisplay);
335
336 infoPtr->rcMonitors = rcExtDisplay;
337
338 /* Now that we know in which area all monitors are located,
339 calculate the monitors selection rectangles on the screen */
340
341 for (Index = 0; Index < infoPtr->MonitorsCount; Index++)
342 {
343 MonSelMonInfoToRect(&infoPtr->MonitorInfo[Index],
344 &rcExtDisplay);
345
346 MonSelScaleRectRelative(&infoPtr->rcExtent,
347 &rcExtDisplay,
348 &infoPtr->rcMonitors,
349 &infoPtr->Monitors[Index].rc);
350 }
351
352 MonSelResetMonitors(infoPtr);
353
354 if (bRepaint)
355 MonSelRepaint(infoPtr);
356 }
357 else if (bRepaint)
358 {
359 InvalidateRect(infoPtr->hSelf,
360 NULL,
361 TRUE);
362 }
363 }
364
365 static BOOL
366 MonSelSetMonitorsInfo(IN OUT PMONITORSELWND infoPtr,
367 IN DWORD dwMonitors,
368 IN const MONSL_MONINFO *MonitorsInfo)
369 {
370 DWORD Index;
371 BOOL Ret = TRUE;
372
373 if (infoPtr->MonitorInfo != NULL)
374 {
375 LocalFree((HLOCAL)infoPtr->MonitorInfo);
376 infoPtr->MonitorInfo = NULL;
377
378 MonSelResetMonitors(infoPtr);
379
380 LocalFree((HLOCAL)infoPtr->Monitors);
381 infoPtr->Monitors = NULL;
382
383 infoPtr->MonitorsCount = 0;
384 }
385
386 if (dwMonitors != 0)
387 {
388 infoPtr->MonitorInfo = (PMONSL_MONINFO)LocalAlloc(LMEM_FIXED,
389 dwMonitors * sizeof(MONSL_MONINFO));
390 if (infoPtr->MonitorInfo != NULL)
391 {
392 infoPtr->Monitors = (PMONSL_MON)LocalAlloc(LMEM_FIXED,
393 dwMonitors * sizeof(MONSL_MON));
394 if (infoPtr->Monitors != NULL)
395 {
396 CopyMemory(infoPtr->MonitorInfo,
397 MonitorsInfo,
398 dwMonitors * sizeof(MONSL_MONINFO));
399 ZeroMemory(infoPtr->Monitors,
400 dwMonitors * sizeof(MONSL_MON));
401
402 for (Index = 0; Index < dwMonitors; Index++)
403 {
404 _stprintf(infoPtr->Monitors[Index].szCaption,
405 _T("%u"),
406 Index + 1);
407 }
408
409 infoPtr->MonitorsCount = dwMonitors;
410
411 if (infoPtr->SelectedMonitor >= (INT)infoPtr->MonitorsCount)
412 infoPtr->SelectedMonitor = -1;
413
414 if (!(infoPtr->ControlExStyle & MSLM_EX_ALLOWSELECTNONE) && infoPtr->SelectedMonitor < 0)
415 infoPtr->SelectedMonitor = 0;
416
417 MonSelUpdateMonitorsInfo(infoPtr,
418 TRUE);
419 }
420 else
421 {
422 LocalFree((HLOCAL)infoPtr->MonitorInfo);
423 infoPtr->MonitorInfo = NULL;
424
425 Ret = FALSE;
426 }
427 }
428 else
429 Ret = FALSE;
430 }
431
432 if (!Ret)
433 infoPtr->SelectedMonitor = -1;
434
435 if (!Ret || dwMonitors == 0)
436 {
437 InvalidateRect(infoPtr->hSelf,
438 NULL,
439 TRUE);
440 }
441
442 return Ret;
443 }
444
445 static DWORD
446 MonSelGetMonitorsInfo(IN PMONITORSELWND infoPtr,
447 IN DWORD dwMonitors,
448 IN OUT PMONSL_MONINFO MonitorsInfo)
449 {
450 if (dwMonitors != 0)
451 {
452 if (dwMonitors > infoPtr->MonitorsCount)
453 dwMonitors = infoPtr->MonitorsCount;
454
455 CopyMemory(MonitorsInfo,
456 infoPtr->MonitorInfo,
457 dwMonitors * sizeof(MONSL_MONINFO));
458 return dwMonitors;
459 }
460 else
461 return infoPtr->MonitorsCount;
462 }
463
464 static BOOL
465 MonSelSetMonitorInfo(IN OUT PMONITORSELWND infoPtr,
466 IN INT Index,
467 IN const MONSL_MONINFO *MonitorsInfo)
468 {
469 if (Index >= 0 && Index < (INT)infoPtr->MonitorsCount)
470 {
471 CopyMemory(&infoPtr->MonitorInfo[Index],
472 MonitorsInfo,
473 sizeof(MONSL_MONINFO));
474
475 MonSelUpdateMonitorsInfo(infoPtr,
476 TRUE);
477 return TRUE;
478 }
479
480 return FALSE;
481 }
482
483 static BOOL
484 MonSelGetMonitorInfo(IN PMONITORSELWND infoPtr,
485 IN INT Index,
486 IN OUT PMONSL_MONINFO MonitorsInfo)
487 {
488 if (Index >= 0 && Index < (INT)infoPtr->MonitorsCount)
489 {
490 CopyMemory(MonitorsInfo,
491 &infoPtr->MonitorInfo[Index],
492 sizeof(MONSL_MONINFO));
493 return TRUE;
494 }
495
496 return FALSE;
497 }
498
499 static BOOL
500 MonSelSetCurSelMonitor(IN OUT PMONITORSELWND infoPtr,
501 IN INT Index,
502 IN BOOL bNotify)
503 {
504 INT PrevSel;
505 BOOL PreventSelect = FALSE;
506 BOOL Ret = FALSE;
507
508 if (Index == -1 || Index < (INT)infoPtr->MonitorsCount)
509 {
510 if (Index != infoPtr->SelectedMonitor)
511 {
512 if ((infoPtr->MonitorInfo[Index].Flags & MSL_MIF_DISABLED) &&
513 !(infoPtr->ControlExStyle & MSLM_EX_ALLOWSELECTDISABLED))
514 {
515 PreventSelect = TRUE;
516 }
517
518 if (!PreventSelect && bNotify)
519 {
520 MONSL_MONNMMONITORCHANGING nmi;
521
522 nmi.PreviousSelected = infoPtr->SelectedMonitor;
523 nmi.AllowChanging = TRUE;
524
525 MonSelNotifyMonitor(infoPtr,
526 MSLN_MONITORCHANGING,
527 Index,
528 &nmi.hdr);
529
530 PreventSelect = (nmi.AllowChanging == FALSE);
531 }
532
533 if (!PreventSelect)
534 {
535 PrevSel = infoPtr->SelectedMonitor;
536 infoPtr->SelectedMonitor = Index;
537
538 if (PrevSel >= 0)
539 {
540 MonSelRepaintMonitor(infoPtr,
541 PrevSel);
542 }
543
544 if (infoPtr->SelectedMonitor >= 0)
545 MonSelRepaintSelected(infoPtr);
546
547 if (bNotify)
548 {
549 MONSL_MONNMHDR nm;
550
551 MonSelNotifyMonitor(infoPtr,
552 MSLN_MONITORCHANGED,
553 Index,
554 &nm);
555 }
556 }
557 }
558
559 Ret = TRUE;
560 }
561
562 return Ret;
563 }
564
565 static VOID
566 MonSelCreate(IN OUT PMONITORSELWND infoPtr)
567 {
568 infoPtr->SelectionFrame.cx = infoPtr->SelectionFrame.cy = 4;
569 infoPtr->Margin.cx = infoPtr->Margin.cy = 20;
570 infoPtr->SelectedMonitor = -1;
571 infoPtr->ControlExStyle = MSLM_EX_ALLOWSELECTDISABLED;
572 return;
573 }
574
575 static VOID
576 MonSelDestroy(IN OUT PMONITORSELWND infoPtr)
577 {
578 /* Free all monitors */
579 MonSelSetMonitorsInfo(infoPtr,
580 0,
581 NULL);
582
583 if (infoPtr->hbrDisabled != NULL)
584 {
585 DeleteObject(infoPtr->hbrDisabled);
586 infoPtr->hbrDisabled = NULL;
587 }
588
589 if (infoPtr->hbmDisabledPattern != NULL)
590 {
591 DeleteObject(infoPtr->hbmDisabledPattern);
592 infoPtr->hbmDisabledPattern = NULL;
593 }
594 }
595
596 static BOOL
597 MonSelSetExtendedStyle(IN OUT PMONITORSELWND infoPtr,
598 IN DWORD dwExtendedStyle)
599 {
600 if (dwExtendedStyle != infoPtr->ControlExStyle)
601 {
602 infoPtr->ControlExStyle = dwExtendedStyle;
603
604 /* Repaint the control */
605 InvalidateRect(infoPtr->hSelf,
606 NULL,
607 TRUE);
608 }
609
610 return TRUE;
611 }
612
613 static DWORD
614 MonSelGetExtendedStyle(IN PMONITORSELWND infoPtr)
615 {
616 return infoPtr->ControlExStyle;
617 }
618
619 static HFONT
620 MonSelGetMonitorFont(IN OUT PMONITORSELWND infoPtr,
621 IN HDC hDC,
622 IN INT Index)
623 {
624 TEXTMETRIC tm;
625 SIZE rcsize;
626 LOGFONT lf;
627 HFONT hPrevFont, hFont;
628 INT len;
629
630 hFont = infoPtr->Monitors[Index].hFont;
631 if (hFont == NULL &&
632 GetObject(infoPtr->hFont,
633 sizeof(LOGFONT),
634 &lf) != 0)
635 {
636 rcsize.cx = infoPtr->Monitors[Index].rc.right - infoPtr->Monitors[Index].rc.left -
637 (2 * infoPtr->SelectionFrame.cx) - 2;
638 rcsize.cy = infoPtr->Monitors[Index].rc.bottom - infoPtr->Monitors[Index].rc.top -
639 (2 * infoPtr->SelectionFrame.cy) - 2;
640 rcsize.cy = (rcsize.cy * 60) / 100;
641
642 len = _tcslen(infoPtr->Monitors[Index].szCaption);
643
644 hPrevFont = SelectObject(hDC,
645 infoPtr->hFont);
646
647 if (GetTextMetrics(hDC,
648 &tm))
649 {
650 lf.lfWeight = FW_SEMIBOLD;
651 lf.lfHeight = -MulDiv(rcsize.cy - tm.tmExternalLeading,
652 GetDeviceCaps(hDC,
653 LOGPIXELSY),
654 72);
655
656 hFont = CreateFontIndirect(&lf);
657 if (hFont != NULL)
658 infoPtr->Monitors[Index].hFont = hFont;
659 }
660
661 SelectObject(hDC,
662 hPrevFont);
663 }
664
665 return hFont;
666 }
667
668 static BOOL
669 MonSelDrawDisabledRect(IN OUT PMONITORSELWND infoPtr,
670 IN HDC hDC,
671 IN const RECT *prc)
672 {
673 BOOL Ret = FALSE;
674
675 if (infoPtr->hbrDisabled == NULL)
676 {
677 static const DWORD Pattern[4] = {0x5555AAAA, 0x5555AAAA, 0x5555AAAA, 0x5555AAAA};
678
679 if (infoPtr->hbmDisabledPattern == NULL)
680 {
681 infoPtr->hbmDisabledPattern = CreateBitmap(8,
682 8,
683 1,
684 1,
685 Pattern);
686 }
687
688 if (infoPtr->hbmDisabledPattern != NULL)
689 infoPtr->hbrDisabled = CreatePatternBrush(infoPtr->hbmDisabledPattern);
690 }
691
692 if (infoPtr->hbrDisabled != NULL)
693 {
694 /* FIXME - implement */
695 }
696
697 return Ret;
698 }
699
700 static VOID
701 MonSelPaint(IN OUT PMONITORSELWND infoPtr,
702 IN HDC hDC,
703 IN const RECT *prcUpdate)
704 {
705 COLORREF crPrevText, crPrevText2;
706 HFONT hFont, hPrevFont;
707 HBRUSH hbBk, hbOldBk;
708 HPEN hpFg, hpOldFg;
709 DWORD Index;
710 RECT rc, rctmp;
711 INT iPrevBkMode;
712
713 hbBk = GetSysColorBrush(COLOR_BACKGROUND);
714 hpFg = CreatePen(PS_SOLID,
715 0,
716 GetSysColor(COLOR_HIGHLIGHTTEXT));
717
718 hbOldBk = SelectObject(hDC,
719 hbBk);
720 hpOldFg = SelectObject(hDC,
721 hpFg);
722 iPrevBkMode = SetBkMode(hDC,
723 TRANSPARENT);
724 crPrevText = SetTextColor(hDC,
725 GetSysColor(COLOR_HIGHLIGHTTEXT));
726
727 for (Index = 0; Index < infoPtr->MonitorsCount; Index++)
728 {
729 MonSelRectToScreen(infoPtr,
730 &infoPtr->Monitors[Index].rc,
731 &rc);
732
733 if (!IntersectRect(&rctmp,
734 &rc,
735 prcUpdate))
736 {
737 continue;
738 }
739
740 if ((INT)Index == infoPtr->SelectedMonitor)
741 {
742 FillRect(hDC,
743 &rc,
744 (HBRUSH)(COLOR_HIGHLIGHT + 1));
745
746 if (infoPtr->HasFocus && !(infoPtr->UIState & UISF_HIDEFOCUS))
747 {
748 /* NOTE: We need to switch the text color to the default, because
749 DrawFocusRect draws a solid line if the text is white! */
750
751 crPrevText2 = SetTextColor(hDC,
752 crPrevText);
753
754 DrawFocusRect(hDC,
755 &rc);
756
757 SetTextColor(hDC,
758 crPrevText2);
759 }
760 }
761
762 InflateRect(&rc,
763 -infoPtr->SelectionFrame.cx,
764 -infoPtr->SelectionFrame.cy);
765
766 Rectangle(hDC,
767 rc.left,
768 rc.top,
769 rc.right,
770 rc.bottom);
771
772 InflateRect(&rc,
773 -1,
774 -1);
775
776 hFont = MonSelGetMonitorFont(infoPtr,
777 hDC,
778 Index);
779 if (hFont != NULL)
780 {
781 hPrevFont = SelectObject(hDC,
782 hFont);
783
784 DrawText(hDC,
785 infoPtr->Monitors[Index].szCaption,
786 -1,
787 &rc,
788 DT_VCENTER | DT_CENTER | DT_NOPREFIX | DT_SINGLELINE);
789
790 SelectObject(hDC,
791 hPrevFont);
792 }
793
794 if (infoPtr->MonitorInfo[Index].Flags & MSL_MIF_DISABLED)
795 {
796 InflateRect(&rc,
797 1,
798 1);
799
800 MonSelDrawDisabledRect(infoPtr,
801 hDC,
802 &rc);
803 }
804 }
805
806 SetTextColor(hDC,
807 crPrevText);
808 SetBkMode(hDC,
809 iPrevBkMode);
810 SelectObject(hDC,
811 hpOldFg);
812 SelectObject(hDC,
813 hbOldBk);
814 }
815
816 static LRESULT CALLBACK
817 MonitorSelWndProc(IN HWND hwnd,
818 IN UINT uMsg,
819 IN WPARAM wParam,
820 IN LPARAM lParam)
821 {
822 PMONITORSELWND infoPtr;
823 LRESULT Ret = 0;
824
825 infoPtr = (PMONITORSELWND)GetWindowLongPtrW(hwnd,
826 0);
827
828 if (infoPtr == NULL && uMsg != WM_CREATE)
829 {
830 goto HandleDefaultMessage;
831 }
832
833 switch (uMsg)
834 {
835 case WM_PAINT:
836 case WM_PRINTCLIENT:
837 {
838 PAINTSTRUCT ps;
839 HDC hDC;
840
841 if (wParam != 0)
842 {
843 if (!GetUpdateRect(hwnd,
844 &ps.rcPaint,
845 TRUE))
846 {
847 break;
848 }
849 hDC = (HDC)wParam;
850 }
851 else
852 {
853 hDC = BeginPaint(hwnd,
854 &ps);
855 if (hDC == NULL)
856 {
857 break;
858 }
859 }
860
861 if (infoPtr->CanDisplay)
862 {
863 MonSelPaint(infoPtr,
864 hDC,
865 &ps.rcPaint);
866 }
867
868 if (wParam == 0)
869 {
870 EndPaint(hwnd,
871 &ps);
872 }
873 break;
874 }
875
876 case WM_LBUTTONDBLCLK:
877 case WM_LBUTTONDOWN:
878 case WM_RBUTTONDOWN:
879 {
880 INT Index;
881 POINT pt;
882
883 pt.x = (LONG)LOWORD(lParam);
884 pt.y = (LONG)HIWORD(lParam);
885
886 Index = MonSelHitTest(infoPtr,
887 &pt);
888 if (Index >= 0 || (infoPtr->ControlExStyle & MSLM_EX_ALLOWSELECTNONE))
889 {
890 MonSelSetCurSelMonitor(infoPtr,
891 Index,
892 TRUE);
893 }
894
895 /* fall through */
896 }
897
898 case WM_MBUTTONDOWN:
899 {
900 if (!infoPtr->HasFocus)
901 SetFocus(hwnd);
902 break;
903 }
904
905 case WM_GETDLGCODE:
906 {
907 INT virtKey;
908
909 virtKey = (lParam != 0 ? (INT)((LPMSG)lParam)->wParam : 0);
910 switch (virtKey)
911 {
912 case VK_TAB:
913 {
914 /* change the UI status */
915 SendMessage(GetAncestor(hwnd,
916 GA_PARENT),
917 WM_CHANGEUISTATE,
918 MAKEWPARAM(UIS_INITIALIZE,
919 0),
920 0);
921 break;
922 }
923 }
924
925 Ret |= DLGC_WANTARROWS;
926 break;
927 }
928
929 case WM_SETFOCUS:
930 {
931 infoPtr->HasFocus = TRUE;
932 MonSelRepaintSelected(infoPtr);
933 break;
934 }
935
936 case WM_KILLFOCUS:
937 {
938 infoPtr->HasFocus = FALSE;
939 MonSelRepaintSelected(infoPtr);
940 break;
941 }
942
943 case WM_UPDATEUISTATE:
944 {
945 DWORD OldUIState = infoPtr->UIState;
946 switch (LOWORD(wParam))
947 {
948 case UIS_SET:
949 infoPtr->UIState |= HIWORD(wParam);
950 break;
951
952 case UIS_CLEAR:
953 infoPtr->UIState &= ~HIWORD(wParam);
954 break;
955 }
956
957 if (infoPtr->UIState != OldUIState)
958 MonSelRepaintSelected(infoPtr);
959 break;
960 }
961
962 case WM_SETFONT:
963 {
964 Ret = (LRESULT)MonSelChangeFont(infoPtr,
965 (HFONT)wParam,
966 (BOOL)LOWORD(lParam));
967 break;
968 }
969
970 case WM_SIZE:
971 {
972 infoPtr->ClientSize.cx = LOWORD(lParam);
973 infoPtr->ClientSize.cy = HIWORD(lParam);
974
975 /* Don't let MonSelUpdateMonitorsInfo repaint the control
976 because this won't work properly in case the control
977 was sized down! */
978 MonSelUpdateMonitorsInfo(infoPtr,
979 FALSE);
980 InvalidateRect(infoPtr->hSelf,
981 NULL,
982 TRUE);
983 break;
984 }
985
986 case WM_GETFONT:
987 {
988 Ret = (LRESULT)infoPtr->hFont;
989 break;
990 }
991
992 case WM_ENABLE:
993 {
994 infoPtr->Enabled = ((BOOL)wParam != FALSE);
995 MonSelRepaint(infoPtr);
996 break;
997 }
998
999 case WM_STYLECHANGED:
1000 {
1001 if (wParam == GWL_STYLE)
1002 {
1003 unsigned int OldEnabled = infoPtr->Enabled;
1004 infoPtr->Enabled = !(((LPSTYLESTRUCT)lParam)->styleNew & WS_DISABLED);
1005
1006 if (OldEnabled != infoPtr->Enabled)
1007 MonSelRepaint(infoPtr);
1008 }
1009 break;
1010 }
1011
1012 case MSLM_SETMONITORSINFO:
1013 {
1014 Ret = MonSelSetMonitorsInfo(infoPtr,
1015 (DWORD)wParam,
1016 (const MONSL_MONINFO *)lParam);
1017 break;
1018 }
1019
1020 case MSLM_GETMONITORSINFO:
1021 {
1022 Ret = MonSelGetMonitorsInfo(infoPtr,
1023 (DWORD)wParam,
1024 (PMONSL_MONINFO)lParam);
1025 break;
1026 }
1027
1028 case MSLM_GETMONITORINFOCOUNT:
1029 {
1030 Ret = infoPtr->MonitorsCount;
1031 break;
1032 }
1033
1034 case MSLM_HITTEST:
1035 {
1036 Ret = MonSelHitTest(infoPtr,
1037 (const POINT *)wParam);
1038 break;
1039 }
1040
1041 case MSLM_SETCURSEL:
1042 {
1043 Ret = MonSelSetCurSelMonitor(infoPtr,
1044 (INT)wParam,
1045 FALSE);
1046 break;
1047 }
1048
1049 case MSLM_GETCURSEL:
1050 {
1051 Ret = infoPtr->SelectedMonitor;
1052 break;
1053 }
1054
1055 case MSLM_SETMONITORINFO:
1056 {
1057 Ret = MonSelSetMonitorInfo(infoPtr,
1058 (INT)wParam,
1059 (const MONSL_MONINFO *)lParam);
1060 break;
1061 }
1062
1063 case MSLM_GETMONITORINFO:
1064 {
1065 Ret = MonSelGetMonitorInfo(infoPtr,
1066 (INT)wParam,
1067 (PMONSL_MONINFO)lParam);
1068 break;
1069 }
1070
1071 case MSLM_SETEXSTYLE:
1072 {
1073 Ret = MonSelSetExtendedStyle(infoPtr,
1074 (DWORD)lParam);
1075 break;
1076 }
1077
1078 case MSLM_GETEXSTYLE:
1079 {
1080 Ret = MonSelGetExtendedStyle(infoPtr);
1081 break;
1082 }
1083
1084 case WM_CREATE:
1085 {
1086 infoPtr = (PMONITORSELWND) HeapAlloc(GetProcessHeap(),
1087 0,
1088 sizeof(MONITORSELWND));
1089 if (infoPtr == NULL)
1090 {
1091 Ret = (LRESULT)-1;
1092 break;
1093 }
1094
1095 ZeroMemory(infoPtr,
1096 sizeof(MONITORSELWND));
1097 infoPtr->hSelf = hwnd;
1098 infoPtr->hNotify = ((LPCREATESTRUCTW)lParam)->hwndParent;
1099 infoPtr->Enabled = !(((LPCREATESTRUCTW)lParam)->style & WS_DISABLED);
1100 infoPtr->UIState = SendMessage(hwnd,
1101 WM_QUERYUISTATE,
1102 0,
1103 0);
1104
1105 SetWindowLongPtrW(hwnd,
1106 0,
1107 (LONG_PTR)infoPtr);
1108
1109 MonSelCreate(infoPtr);
1110 break;
1111 }
1112
1113 case WM_DESTROY:
1114 {
1115 MonSelDestroy(infoPtr);
1116
1117 HeapFree(GetProcessHeap(),
1118 0,
1119 infoPtr);
1120 SetWindowLongPtrW(hwnd,
1121 0,
1122 (DWORD_PTR)NULL);
1123 break;
1124 }
1125
1126 default:
1127 {
1128 HandleDefaultMessage:
1129 Ret = DefWindowProcW(hwnd,
1130 uMsg,
1131 wParam,
1132 lParam);
1133 break;
1134 }
1135 }
1136
1137 return Ret;
1138 }
1139
1140 BOOL
1141 RegisterMonitorSelectionControl(IN HINSTANCE hInstance)
1142 {
1143 WNDCLASS wc = {0};
1144
1145 wc.style = CS_DBLCLKS;
1146 wc.lpfnWndProc = MonitorSelWndProc;
1147 wc.cbWndExtra = sizeof(PMONITORSELWND);
1148 wc.hInstance = hInstance;
1149 wc.hCursor = LoadCursorW(NULL,
1150 (LPWSTR)IDC_ARROW);
1151 wc.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
1152 wc.lpszClassName = szMonitorSelWndClass;
1153
1154 return RegisterClass(&wc) != 0;
1155 }
1156
1157 VOID
1158 UnregisterMonitorSelectionControl(IN HINSTANCE hInstance)
1159 {
1160 UnregisterClassW(szMonitorSelWndClass,
1161 hInstance);
1162 }