Skip to content

Commit 7b8ddbe

Browse files
committed
[ui] improve notification dialog handling
* Use MessageBox()'s MB_ constants instead of redefining our own. * Fix the *BROKEN* 200% scaling that Microsoft uses for warnings, that includes a pixel that should have been set to transparent but that instead was set to white. * This'll allow us to switch to using our Dark Mode compatible notifications dialogs in a future commit, instead of relying on the non Dark Mode compatible MessageBox().
1 parent 99c04a9 commit 7b8ddbe

File tree

6 files changed

+134
-65
lines changed

6 files changed

+134
-65
lines changed

src/net.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -931,10 +931,10 @@ static DWORD WINAPI DownloadISOThread(LPVOID param)
931931
SendMessage(hMainDialog, UM_PROGRESS_EXIT, 0, 0);
932932
if (SCODE_CODE(ErrorStatus) == ERROR_CANCELLED) {
933933
uprintf("Download cancelled by user");
934-
Notification(MSG_INFO, NULL, NULL, lmprintf(MSG_211), lmprintf(MSG_041));
934+
Notification(MB_ICONINFORMATION | MB_CLOSE, lmprintf(MSG_211), lmprintf(MSG_041));
935935
PrintInfo(0, MSG_211);
936936
} else {
937-
Notification(MSG_ERROR, NULL, NULL, lmprintf(MSG_194, GetShortName(url)), lmprintf(MSG_043, WindowsErrorString()));
937+
Notification(MB_ICONERROR | MB_CLOSE, lmprintf(MSG_194, GetShortName(url)), lmprintf(MSG_043, WindowsErrorString()));
938938
PrintInfo(0, MSG_212);
939939
}
940940
} else {

src/rufus.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2823,11 +2823,11 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
28232823
#if defined(ALPHA)
28242824
// Add a VERY ANNOYING popup for Alpha releases, so that people don't start redistributing them
28252825
MessageBoxA(NULL, "This is an Alpha version of " APPLICATION_NAME " - It is meant to be used for "
2826-
"testing ONLY and should NOT be distributed as a release.", "ALPHA VERSION", MSG_INFO);
2826+
"testing ONLY and should NOT be distributed as a release.", "ALPHA VERSION", MB_ICONINFORMATION);
28272827
#elif defined(TEST)
28282828
// Same thing for Test releases
28292829
MessageBoxA(NULL, "This is a Test version of " APPLICATION_NAME " - It is meant to be used for "
2830-
"testing ONLY and should NOT be distributed as a release.", "TEST VERSION", MSG_INFO);
2830+
"testing ONLY and should NOT be distributed as a release.", "TEST VERSION", MB_ICONINFORMATION);
28312831
#endif
28322832
SetDarkModeForChild(hDlg);
28332833
SubclassStatusBar(hStatus);
@@ -3022,7 +3022,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
30223022
break;
30233023

30243024
case UM_NO_UPDATE:
3025-
Notification(MSG_INFO, NULL, NULL, lmprintf(MSG_243), lmprintf(MSG_247));
3025+
Notification(MB_ICONINFORMATION | MB_CLOSE, lmprintf(MSG_243), lmprintf(MSG_247));
30263026
// Need to manually set focus back to "Check Now" for tabbing to work
30273027
SendMessage(hUpdatesDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hUpdatesDlg, IDC_CHECK_NOW), TRUE);
30283028
break;
@@ -3061,7 +3061,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
30613061
if (GetProcessSearch(SEARCH_PROCESS_TIMEOUT, 0x06, TRUE)) {
30623062
char title[128];
30633063
ComboBox_GetTextU(hDeviceList, title, sizeof(title));
3064-
if (!Notification(MSG_WARNING_QUESTION, NULL, NULL, title, lmprintf(MSG_132)))
3064+
if (Notification(MB_ICONWARNING | MB_YESNO, title, lmprintf(MSG_132)) != IDYES)
30653065
goto aborted_start;
30663066
}
30673067
PrintStatus(0, MSG_142);
@@ -3142,7 +3142,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
31423142
SendMessage(hProgress, PBM_SETSTATE, (WPARAM)PBST_PAUSED, 0);
31433143
SetTaskbarProgressState(TASKBAR_PAUSED);
31443144
PrintInfo(0, MSG_211);
3145-
Notification(MSG_INFO, NULL, NULL, lmprintf(MSG_211), lmprintf(MSG_041));
3145+
Notification(MB_ICONINFORMATION | MB_CLOSE, lmprintf(MSG_211), lmprintf(MSG_041));
31463146
} else {
31473147
SendMessage(hProgress, PBM_SETSTATE, (WPARAM)PBST_ERROR, 0);
31483148
SetTaskbarProgressState(TASKBAR_ERROR);
@@ -3190,7 +3190,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
31903190
CyclePort(index);
31913191
}
31923192
}
3193-
Notification(MSG_ERROR, NULL, NULL, lmprintf(MSG_042), lmprintf(MSG_043, StrError(ErrorStatus, FALSE)));
3193+
Notification(MB_ICONERROR | MB_CLOSE, lmprintf(MSG_042), lmprintf(MSG_043, StrError(ErrorStatus, FALSE)));
31943194
}
31953195
}
31963196
ErrorStatus = 0;

src/rufus.h

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -244,13 +244,7 @@ enum user_message_type {
244244
};
245245

246246
/* Custom notifications */
247-
enum notification_type {
248-
MSG_INFO,
249-
MSG_WARNING,
250-
MSG_ERROR,
251-
MSG_QUESTION,
252-
MSG_WARNING_QUESTION
253-
};
247+
#define MB_CLOSE 0x0F
254248
typedef INT_PTR (CALLBACK *Callback_t)(HWND, UINT, WPARAM, LPARAM);
255249
typedef struct {
256250
WORD id;
@@ -805,7 +799,8 @@ extern INT_PTR CreateAboutBox(void);
805799
extern BOOL CreateTooltip(HWND hControl, const char* message, int duration);
806800
extern void DestroyTooltip(HWND hWnd);
807801
extern void DestroyAllTooltips(void);
808-
extern BOOL Notification(int type, const char* dont_display_setting, const notification_info* more_info, char* title, char* format, ...);
802+
extern INT_PTR NotificationEx(int type, const char* dont_display_setting, const notification_info* more_info, char* title, char* format, ...);
803+
#define Notification(type, ...) NotificationEx(type, NULL, NULL, __VA_ARGS__)
809804
extern int CustomSelectionDialog(int style, char* title, char* message, char** choices, int size, int mask, int username_index);
810805
#define SelectionDialog(title, message, choices, size) CustomSelectionDialog(BS_AUTORADIOBUTTON, title, message, choices, size, 1, -1)
811806
extern void ListDialog(char* title, char* message, char** items, int size);

src/rufus.rc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
3333
IDD_DIALOG DIALOGEX 12, 12, 232, 326
3434
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
3535
EXSTYLE WS_EX_ACCEPTFILES
36-
CAPTION "Rufus 4.10.2272"
36+
CAPTION "Rufus 4.10.2273"
3737
FONT 9, "Segoe UI Symbol", 400, 0, 0x0
3838
BEGIN
3939
LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP
@@ -407,8 +407,8 @@ END
407407
//
408408

409409
VS_VERSION_INFO VERSIONINFO
410-
FILEVERSION 4,10,2272,0
411-
PRODUCTVERSION 4,10,2272,0
410+
FILEVERSION 4,10,2273,0
411+
PRODUCTVERSION 4,10,2273,0
412412
FILEFLAGSMASK 0x3fL
413413
#ifdef _DEBUG
414414
FILEFLAGS 0x1L
@@ -426,13 +426,13 @@ BEGIN
426426
VALUE "Comments", "https://rufus.ie"
427427
VALUE "CompanyName", "Akeo Consulting"
428428
VALUE "FileDescription", "Rufus"
429-
VALUE "FileVersion", "4.10.2272"
429+
VALUE "FileVersion", "4.10.2273"
430430
VALUE "InternalName", "Rufus"
431431
VALUE "LegalCopyright", "� 2011-2025 Pete Batard (GPL v3)"
432432
VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html"
433433
VALUE "OriginalFilename", "rufus-4.10.exe"
434434
VALUE "ProductName", "Rufus"
435-
VALUE "ProductVersion", "4.10.2272"
435+
VALUE "ProductVersion", "4.10.2273"
436436
END
437437
END
438438
BLOCK "VarFileInfo"

src/stdlg.c

Lines changed: 117 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ static char **szDialogItem;
5656
static int nDialogItems;
5757
static HWND hUpdatesDlg;
5858
static const SETTEXTEX friggin_microsoft_unicode_amateurs = { ST_DEFAULT, CP_UTF8 };
59-
static BOOL notification_is_question;
59+
static int notification_type;
6060
static const notification_info* notification_more_info;
6161
static const char* notification_dont_display_setting;
6262
static WNDPROC update_original_proc = NULL;
@@ -464,6 +464,59 @@ INT_PTR CreateAboutBox(void)
464464
return r;
465465
}
466466

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+
467520
/*
468521
* We use our own MessageBox for notifications to have greater control (center, no close button, etc)
469522
*/
@@ -512,21 +565,55 @@ INT_PTR CALLBACK NotificationCallback(HWND hDlg, UINT message, WPARAM wParam, LP
512565
background_brush = GetSysColorBrush(COLOR_WINDOW);
513566
separator_brush = GetSysColorBrush(COLOR_3DLIGHT);
514567
buttonface_brush = GetSysColorBrush(COLOR_BTNFACE);
515-
SetTitleBarIcon(hDlg);
568+
SetTitleBarIcon(hDlg); // ??? This doesn't seem to work here
516569
CenterDialog(hDlg, NULL);
517570
// 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;
520589
}
590+
if (Static_SetIcon(GetDlgItem(hDlg, IDC_NOTIFICATION_ICON), hMessageIcon) == 0)
591+
uprintf("Could not set the notification dialog icon");
521592
// Set the dialog title
522-
if (szMessageTitle != NULL) {
593+
if (szMessageTitle != NULL)
523594
SetWindowTextU(hDlg, szMessageTitle);
524-
}
525595
// 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));
529600
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;
530617
}
531618
hCtrl = GetDlgItem(hDlg, IDC_DONT_DISPLAY_AGAIN);
532619
if (notification_dont_display_setting != NULL) {
@@ -572,12 +659,10 @@ INT_PTR CALLBACK NotificationCallback(HWND hDlg, UINT message, WPARAM wParam, LP
572659
case WM_CTLCOLORSTATIC:
573660
// Change the background colour for static text and icon
574661
SetBkMode((HDC)wParam, TRANSPARENT);
575-
if ((HWND)lParam == GetDlgItem(hDlg, IDC_NOTIFICATION_LINE)) {
662+
if ((HWND)lParam == GetDlgItem(hDlg, IDC_NOTIFICATION_LINE))
576663
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))
579665
return (INT_PTR)buttonface_brush;
580-
}
581666
return (INT_PTR)background_brush;
582667
case WM_NCHITTEST:
583668
// Check coordinates to prevent resize actions
@@ -592,14 +677,23 @@ INT_PTR CALLBACK NotificationCallback(HWND hDlg, UINT message, WPARAM wParam, LP
592677
safe_delete_object(hDlgFont);
593678
break;
594679
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);
595683
switch (LOWORD(wParam)) {
596-
case IDOK:
597-
case IDCANCEL:
598684
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;
599690
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
603697
EndDialog(hDlg, LOWORD(wParam));
604698
return (INT_PTR)TRUE;
605699
case IDC_MORE_INFO:
@@ -622,9 +716,9 @@ INT_PTR CALLBACK NotificationCallback(HWND hDlg, UINT message, WPARAM wParam, LP
622716
/*
623717
* Display a custom notification
624718
*/
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, ...)
626720
{
627-
BOOL ret;
721+
INT_PTR ret;
628722
va_list args;
629723

630724
dialog_showing++;
@@ -639,29 +733,9 @@ BOOL Notification(int type, const char* dont_display_setting, const notification
639733
va_end(args);
640734
szMessageText[LOC_MESSAGE_SIZE - 1] = 0;
641735
notification_more_info = more_info;
642-
notification_is_question = FALSE;
736+
notification_type = type;
643737
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);
665739
safe_free(szMessageText);
666740
safe_free(szMessageTitle);
667741
dialog_showing--;
@@ -1533,7 +1607,7 @@ BOOL SetUpdateCheck(void)
15331607
#endif
15341608
more_info.id = IDD_UPDATE_POLICY;
15351609
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);
15371611
#if !defined(_DEBUG)
15381612
}
15391613
#endif

src/wue.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -642,7 +642,7 @@ int SetWinToGoIndex(void)
642642
notification_info more_info;
643643
more_info.id = MORE_INFO_URL;
644644
more_info.url = WPPRECORDER_MORE_INFO_URL;
645-
Notification(MSG_INFO, NULL, &more_info, lmprintf(MSG_128, "Windows To Go"), lmprintf(MSG_133));
645+
NotificationEx(MB_ICONINFORMATION | MB_CLOSE, NULL, &more_info, lmprintf(MSG_128, "Windows To Go"), lmprintf(MSG_133));
646646
}
647647
}
648648

0 commit comments

Comments
 (0)