@@ -56,7 +56,7 @@ static char **szDialogItem;
56
56
static int nDialogItems ;
57
57
static HWND hUpdatesDlg ;
58
58
static const SETTEXTEX friggin_microsoft_unicode_amateurs = { ST_DEFAULT , CP_UTF8 };
59
- static BOOL notification_is_question ;
59
+ static int notification_type ;
60
60
static const notification_info * notification_more_info ;
61
61
static const char * notification_dont_display_setting ;
62
62
static WNDPROC update_original_proc = NULL ;
@@ -464,6 +464,59 @@ INT_PTR CreateAboutBox(void)
464
464
return r ;
465
465
}
466
466
467
+ // The warning icon from the OS is *BROKEN* in dark mode at 200% scaling (one of the
468
+ // pixels that should be transparent is set to white), so we fix it. Thanks Microsoft!
469
+ HICON FixWarningIcon (HICON hIcon )
470
+ {
471
+ void * bits = NULL ;
472
+ ICONINFO info , new_info ;
473
+ BITMAP bmp ;
474
+ BITMAPINFO bmi = { 0 };
475
+ HBITMAP dib , src_obj , dst_obj ;
476
+ HDC hdc , src_dc , dst_dc ;
477
+ DWORD * pixels ;
478
+
479
+ GetIconInfo (hIcon , & info );
480
+ GetObject (info .hbmColor , sizeof (bmp ), & bmp );
481
+ bmi .bmiHeader .biSize = sizeof (BITMAPINFOHEADER );
482
+ bmi .bmiHeader .biWidth = bmp .bmWidth ;
483
+ bmi .bmiHeader .biHeight = - bmp .bmHeight ;
484
+ bmi .bmiHeader .biPlanes = 1 ;
485
+ bmi .bmiHeader .biBitCount = 32 ;
486
+ bmi .bmiHeader .biCompression = BI_RGB ;
487
+
488
+ hdc = GetDC (NULL );
489
+ dib = CreateDIBSection (hdc , & bmi , DIB_RGB_COLORS , & bits , NULL , 0 );
490
+ ReleaseDC (NULL , hdc );
491
+ if (dib == NULL )
492
+ return hIcon ;
493
+ src_dc = CreateCompatibleDC (NULL );
494
+ dst_dc = CreateCompatibleDC (NULL );
495
+ src_obj = SelectObject (src_dc , info .hbmColor );
496
+ dst_obj = SelectObject (dst_dc , dib );
497
+
498
+ BitBlt (dst_dc , 0 , 0 , bmp .bmWidth , bmp .bmHeight , src_dc , 0 , 0 , SRCCOPY );
499
+
500
+ SelectObject (src_dc , src_obj );
501
+ SelectObject (dst_dc , dst_obj );
502
+ DeleteDC (src_dc );
503
+ DeleteDC (dst_dc );
504
+ pixels = (DWORD * )bits ;
505
+ // Set the problematic pixel, at (13,2), to transparent
506
+ pixels [2 * bmp .bmWidth + 13 ] = 0x00000000 ;
507
+
508
+ new_info .fIcon = TRUE;
509
+ new_info .xHotspot = info .xHotspot ;
510
+ new_info .yHotspot = info .yHotspot ;
511
+ new_info .hbmMask = info .hbmMask ;
512
+ new_info .hbmColor = dib ;
513
+
514
+ hIcon = CreateIconIndirect (& new_info );
515
+ DeleteObject (info .hbmColor );
516
+ DeleteObject (info .hbmMask );
517
+ return hIcon ;
518
+ }
519
+
467
520
/*
468
521
* We use our own MessageBox for notifications to have greater control (center, no close button, etc)
469
522
*/
@@ -512,21 +565,55 @@ INT_PTR CALLBACK NotificationCallback(HWND hDlg, UINT message, WPARAM wParam, LP
512
565
background_brush = GetSysColorBrush (COLOR_WINDOW );
513
566
separator_brush = GetSysColorBrush (COLOR_3DLIGHT );
514
567
buttonface_brush = GetSysColorBrush (COLOR_BTNFACE );
515
- SetTitleBarIcon (hDlg );
568
+ SetTitleBarIcon (hDlg ); // ??? This doesn't seem to work here
516
569
CenterDialog (hDlg , NULL );
517
570
// Change the default icon
518
- if (Static_SetIcon (GetDlgItem (hDlg , IDC_NOTIFICATION_ICON ), hMessageIcon ) == 0 ) {
519
- uprintf ("Could not set dialog icon\n" );
571
+ switch (notification_type & 0xF0 ) {
572
+ case MB_ICONERROR :
573
+ hMessageIcon = LoadIcon (NULL , IDI_ERROR );
574
+ break ;
575
+ case MB_ICONWARNING :
576
+ hMessageIcon = LoadIcon (NULL , IDI_WARNING );
577
+ // I really have no idea at what scaling factors Microsoft switches icons.
578
+ // However, the 200% icon has a jarring white pixel in dark mode, because
579
+ // Microsoft forgot to set that pixel to transparent, that we need to fix.
580
+ if (fScale > 1.75f && fScale < 2.5f )
581
+ hMessageIcon = FixWarningIcon (hMessageIcon );
582
+ break ;
583
+ case MB_ICONQUESTION :
584
+ hMessageIcon = LoadIcon (NULL , IDI_QUESTION );
585
+ break ;
586
+ default :
587
+ hMessageIcon = LoadIcon (NULL , IDI_INFORMATION );
588
+ break ;
520
589
}
590
+ if (Static_SetIcon (GetDlgItem (hDlg , IDC_NOTIFICATION_ICON ), hMessageIcon ) == 0 )
591
+ uprintf ("Could not set the notification dialog icon" );
521
592
// Set the dialog title
522
- if (szMessageTitle != NULL ) {
593
+ if (szMessageTitle != NULL )
523
594
SetWindowTextU (hDlg , szMessageTitle );
524
- }
525
595
// Enable/disable the buttons and set text
526
- if (!notification_is_question ) {
527
- SetWindowTextU (GetDlgItem (hDlg , IDNO ), lmprintf (MSG_006 ));
528
- } else {
596
+ switch (notification_type & 0x0F ) {
597
+ case MB_OKCANCEL :
598
+ SetWindowTextU (GetDlgItem (hDlg , IDYES ), "OK" );
599
+ SetWindowTextU (GetDlgItem (hDlg , IDNO ), lmprintf (MSG_007 ));
529
600
ShowWindow (GetDlgItem (hDlg , IDYES ), SW_SHOW );
601
+ break ;
602
+ case MB_YESNO :
603
+ SetWindowTextU (GetDlgItem (hDlg , IDYES ), lmprintf (MSG_008 ));
604
+ SetWindowTextU (GetDlgItem (hDlg , IDNO ), lmprintf (MSG_009 ));
605
+ ShowWindow (GetDlgItem (hDlg , IDYES ), SW_SHOW );
606
+ break ;
607
+ case MB_OK :
608
+ SetWindowTextU (GetDlgItem (hDlg , IDYES ), "OK" );
609
+ break ;
610
+ case MB_ABORTRETRYIGNORE :
611
+ // TODO: Look at the standard Abort/Retry/Ignore MessageBox and replicate that
612
+ assert (FALSE);
613
+ break ;
614
+ default : // One single 'Close' button
615
+ SetWindowTextU (GetDlgItem (hDlg , IDNO ), lmprintf (MSG_006 ));
616
+ break ;
530
617
}
531
618
hCtrl = GetDlgItem (hDlg , IDC_DONT_DISPLAY_AGAIN );
532
619
if (notification_dont_display_setting != NULL ) {
@@ -572,12 +659,10 @@ INT_PTR CALLBACK NotificationCallback(HWND hDlg, UINT message, WPARAM wParam, LP
572
659
case WM_CTLCOLORSTATIC :
573
660
// Change the background colour for static text and icon
574
661
SetBkMode ((HDC )wParam , TRANSPARENT );
575
- if ((HWND )lParam == GetDlgItem (hDlg , IDC_NOTIFICATION_LINE )) {
662
+ if ((HWND )lParam == GetDlgItem (hDlg , IDC_NOTIFICATION_LINE ))
576
663
return (INT_PTR )separator_brush ;
577
- }
578
- if ((HWND )lParam == GetDlgItem (hDlg , IDC_DONT_DISPLAY_AGAIN )) {
664
+ if ((HWND )lParam == GetDlgItem (hDlg , IDC_DONT_DISPLAY_AGAIN ))
579
665
return (INT_PTR )buttonface_brush ;
580
- }
581
666
return (INT_PTR )background_brush ;
582
667
case WM_NCHITTEST :
583
668
// Check coordinates to prevent resize actions
@@ -592,14 +677,23 @@ INT_PTR CALLBACK NotificationCallback(HWND hDlg, UINT message, WPARAM wParam, LP
592
677
safe_delete_object (hDlgFont );
593
678
break ;
594
679
case WM_COMMAND :
680
+ // TODO: This is brittle... and I don't think we use it anyway
681
+ if (LOWORD (wParam ) != IDC_MORE_INFO && IsDlgButtonChecked (hDlg , IDC_DONT_DISPLAY_AGAIN ) == BST_CHECKED )
682
+ WriteSettingBool (SETTING_DISABLE_SECURE_BOOT_NOTICE , TRUE);
595
683
switch (LOWORD (wParam )) {
596
- case IDOK :
597
- case IDCANCEL :
598
684
case IDYES :
685
+ // Return IDOK for calls that expect it
686
+ if ((notification_type & 0x0F ) == MB_OKCANCEL || (notification_type & 0x0F ) == MB_OK )
687
+ wParam = IDOK ;
688
+ EndDialog (hDlg , LOWORD (wParam ));
689
+ return (INT_PTR )TRUE;
599
690
case IDNO :
600
- if (IsDlgButtonChecked (hDlg , IDC_DONT_DISPLAY_AGAIN ) == BST_CHECKED ) {
601
- WriteSettingBool (SETTING_DISABLE_SECURE_BOOT_NOTICE , TRUE);
602
- }
691
+ // Return IDCANCEL for calls that expect it
692
+ if ((notification_type & 0x0F ) == MB_OKCANCEL )
693
+ wParam = IDCANCEL ;
694
+ EndDialog (hDlg , LOWORD (wParam ));
695
+ return (INT_PTR )TRUE;
696
+ case IDRETRY : // TODO: implement this or drop the one call that requests it
603
697
EndDialog (hDlg , LOWORD (wParam ));
604
698
return (INT_PTR )TRUE;
605
699
case IDC_MORE_INFO :
@@ -622,9 +716,9 @@ INT_PTR CALLBACK NotificationCallback(HWND hDlg, UINT message, WPARAM wParam, LP
622
716
/*
623
717
* Display a custom notification
624
718
*/
625
- BOOL Notification (int type , const char * dont_display_setting , const notification_info * more_info , char * title , char * format , ...)
719
+ INT_PTR NotificationEx (int type , const char * dont_display_setting , const notification_info * more_info , char * title , char * format , ...)
626
720
{
627
- BOOL ret ;
721
+ INT_PTR ret ;
628
722
va_list args ;
629
723
630
724
dialog_showing ++ ;
@@ -639,29 +733,9 @@ BOOL Notification(int type, const char* dont_display_setting, const notification
639
733
va_end (args );
640
734
szMessageText [LOC_MESSAGE_SIZE - 1 ] = 0 ;
641
735
notification_more_info = more_info ;
642
- notification_is_question = FALSE ;
736
+ notification_type = type ;
643
737
notification_dont_display_setting = dont_display_setting ;
644
-
645
- switch (type ) {
646
- case MSG_WARNING_QUESTION :
647
- notification_is_question = TRUE;
648
- // Fall through
649
- case MSG_WARNING :
650
- hMessageIcon = LoadIcon (NULL , IDI_WARNING );
651
- break ;
652
- case MSG_ERROR :
653
- hMessageIcon = LoadIcon (NULL , IDI_ERROR );
654
- break ;
655
- case MSG_QUESTION :
656
- hMessageIcon = LoadIcon (NULL , IDI_QUESTION );
657
- notification_is_question = TRUE;
658
- break ;
659
- case MSG_INFO :
660
- default :
661
- hMessageIcon = LoadIcon (NULL , IDI_INFORMATION );
662
- break ;
663
- }
664
- ret = (MyDialogBox (hMainInstance , IDD_NOTIFICATION , hMainDialog , NotificationCallback ) == IDYES );
738
+ ret = MyDialogBox (hMainInstance , IDD_NOTIFICATION , hMainDialog , NotificationCallback );
665
739
safe_free (szMessageText );
666
740
safe_free (szMessageTitle );
667
741
dialog_showing -- ;
@@ -1533,7 +1607,7 @@ BOOL SetUpdateCheck(void)
1533
1607
#endif
1534
1608
more_info .id = IDD_UPDATE_POLICY ;
1535
1609
more_info .callback = UpdateCallback ;
1536
- enable_updates = Notification ( MSG_QUESTION , NULL , & more_info , lmprintf (MSG_004 ), lmprintf (MSG_005 ));
1610
+ enable_updates = ( NotificationEx ( MB_ICONQUESTION | MB_YESNO , NULL , & more_info , lmprintf (MSG_004 ), lmprintf (MSG_005 )) == IDYES );
1537
1611
#if !defined(_DEBUG )
1538
1612
}
1539
1613
#endif
0 commit comments