Merge pull request #5760 from RaiKoHoff/dev_master

add: PasteBoard: opt-out 'Don't ask again' on closing modified...
This commit is contained in:
Rainer Kottenhoff 2026-04-24 12:40:50 +02:00 committed by GitHub
commit d351981a9b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 276 additions and 101 deletions

View File

@ -46,6 +46,8 @@ Each language is one `styleLexXXX.c` defining an `EDITLEXER` struct (see existin
27+ locales under `np3_LANG_COUNTRY\`. Language packs build as separate DLLs.
**Invariant:** every `IDS_MUI_*` defined in `common_res.h` must exist in **all** `strings_*.rc` files. A missing entry breaks the corresponding language DLL build. For bulk insertions across locales, use a `.venv/Scripts/python.exe` script — `sed`/`perl` `\n` escaping is unreliable in Cygwin.
### Adding a string resource
1. `#define IDS_MUI_XXX <id>` in `language\common_res.h` (13xxx errors/warnings, 14xxx info/prompts).
@ -128,6 +130,10 @@ Vendored 5.5.8 / 5.4.6 with NP3 patches under `np3_patches\`. Versions in `scint
Use existing structs (`Globals`, `Settings`, `Settings2`, `Flags`, `Paths`). Don't add new globals.
### Dialog return values (`InfoBoxLng`)
`InfoBoxLng()` returns `MAKELONG(button, mode)` — never compare/switch on the raw return when the suppression key is non-NULL: a saved-answer replay sets HIWORD too, so `result == IDNO` is false. Use `IsYesOkay()` / `IsRetryContinue()` / `IsNoCancelClose()` (in `src\Dialogs.h`), or extract via `INFOBOX_ANSW(r)` (LOWORD) and `INFOBOX_MODE(r)` (HIWORD). Switching on the raw value is a latent bug if a suppression key is ever added.
### Portable INI design
- INI beside the exe. No registry. Runs on defaults if none exists (user creates via "Save Settings Now").
@ -138,7 +144,7 @@ Use existing structs (`Globals`, `Settings`, `Settings2`, `Flags`, `Paths`). Don
- **`bIniFileFromScratch`** is set when INI is 0 bytes, cleared after `SaveAllSettings()`. While set, `MuiLanguage.c` suppresses writing `PreferredLanguageLocaleName`.
- **Empty lexer sections are pruned** in `Style_ToIniSection()` via `IniSectionGetKeyCount()` — only sections with non-default styles persist.
- MiniPath uses the same pattern (`minipath\src\Config.cpp`).
- **New `Settings2` (or other INI) params must be documented as commented entries in `Build\Notepad3.ini`.**
- **New `Settings2` (or other INI) params must be documented in BOTH places**: a commented entry under `[Settings2]` in `Build\Notepad3.ini` AND a `#### \`Name=default\`` heading + prose paragraph in the matching topical section of `readme\config\Configuration.md` (the user-facing reference). Updating only the INI is incomplete.
### Save/Load macros (`src\Config\Config.cpp`)

View File

@ -16,6 +16,7 @@ SettingsVersion=5
;DefaultDirectory=
;DefaultExtension=txt
;DenyVirtualSpaceAccess=0
;DiscardOnClosingUntitledPasteBoard=0 ;(0/1) {when set, the close-modified prompt for an Untitled (no file path) document in PasteBoard / clipboard-monitoring mode (/B) offers a "Don't show this dialog again" opt-out checkbox; after opting out, the chosen action repeats silently on subsequent closes; has no effect when PasteBoard mode is not active}
;filebrowser.exe=minipath.exe
;FileCheckInterval=2000 ;(min: 200[msec] - if equal or less, notify immediately)
;FileWatchingMethod=0 ;(0=both[default], 1=poll-only, 2=push-only)
@ -31,6 +32,7 @@ SettingsVersion=5
;PasteBoardSeparator= ;(-> <use current EOL>) {separator pre-pended before each new clipboard entry (pasted at caret) in pasteboard mode; suppressed on first paste after enable and when caret is at a line start; empty=no separator; supports \r\n, \n, \t, \xHH; include newlines explicitly e.g. "\r\n---\r\n" for a dashed separator line}
;PasteBoardDebounceMs=200 ;(min: 0, max: 5000[msec]) {debounce interval for clipboard monitoring}
;PasteBoardAddTimestamp=0 ;(0/1) {prepend [HH:MM:SS] timestamp to each pasted entry in pasteboard mode}
;PasteBoardInitialShowMs=1500 ;(min: 500, max: 5000[msec]) {when launched with /B and /I together: show the window normally for this duration so the auto-pasted clipboard is visible, then minimize. Has no effect unless both /B and /I are passed.}
;NoFadeHidden=0
;NoFileVariables=0
;NoHTMLGuess=0

View File

@ -79,6 +79,7 @@ External tool, **not built from source**. Pre-built exes under `grepWin\portable
## Localization
- 26 locales under `language\np3_LANG_COUNTRY\`. Language DLLs are separate projects in the solution.
- **Invariant: every `IDS_MUI_*` defined in `common_res.h` must exist in all 26 `strings_*.rc` files.** A missing entry breaks the corresponding language DLL build. For bulk insertions across locales, use a `.venv/Scripts/python.exe` script — `sed`/`perl` `\n` escaping is unreliable in Cygwin.
- **`.rc` files are UTF-8 WITHOUT BOM, CRLF line endings.** Never write with BOM. Use `Build\rc_to_utf8.cmd` to strip accidental BOMs. In PowerShell use `[System.Text.UTF8Encoding]::new($false)`; in Python write `\r\n` explicitly.
- **`Build\Notepad3.ini`, `Build\minipath.ini` are UTF-8 WITH BOM** (`EF BB BF`). Preserve it.
@ -99,7 +100,7 @@ External tool, **not built from source**. Pre-built exes under `grepWin\portable
- **`bIniFileFromScratch`** is set when INI is 0 bytes, cleared after `SaveAllSettings()`. While set, `MuiLanguage.c` suppresses writing `PreferredLanguageLocaleName` to keep fresh INIs clean.
- **Empty lexer sections are pruned** in `Style_ToIniSection()` via `IniSectionGetKeyCount()` after `Style_CanonicalSectionToIniCache()` establishes order — only sections with non-default styles persist.
- MiniPath follows the same pattern (`minipath\src\Config.cpp`).
- **New `Settings2` (or other INI) params must be documented as commented entries in `Build\Notepad3.ini`.**
- **New `Settings2` (or other INI) params must be documented in BOTH places**: a commented entry under `[Settings2]` in `Build\Notepad3.ini` AND a `#### \`Name=default\`` heading + prose paragraph in the matching topical section of `readme\config\Configuration.md` (the user-facing reference). Updating only the INI is incomplete.
### Save/Load macros (`src\Config\Config.cpp`)
@ -167,6 +168,7 @@ Supported: Win32 (x86), x64, x64_AVX2, ARM64. **ARM 32-bit is not supported**
- **Scintilla**: always use `SciCall.h` wrappers. Add missing wrappers there. Naming: `DeclareSciCall{V|R}{0|01|1|2}` — V=void, R=return; 0/1/2 = param count; `01` = lParam-only. The `msg` arg is the suffix after `SCI_`.
- **Global state**: use existing structs (`Globals`, `Settings`, `Settings2`, `Flags`, `Paths`); don't add new globals.
- **Undo/redo**: use `_BEGIN_UNDO_ACTION_` / `_END_UNDO_ACTION_` macros (`Notepad3.h`) for grouping; they also throttle notifications during bulk edits.
- **`InfoBoxLng()` returns `MAKELONG(button, mode)`** — never compare/switch on the raw return when the suppression key is non-NULL: a saved-answer replay sets HIWORD too, so `result == IDNO` is false. Use `IsYesOkay()` / `IsRetryContinue()` / `IsNoCancelClose()` (in `src/Dialogs.h`), or extract via `INFOBOX_ANSW(r)` (LOWORD) and `INFOBOX_MODE(r)` (HIWORD). Switching on the raw value is a latent bug if a suppression key is ever added.
### WriteAccessBuf — dangling pointer anti-pattern

View File

@ -100,7 +100,7 @@ END
STRINGTABLE
BEGIN
IDS_MUI_APPTITLE_ELEVATED "%s : Erhöhte Rechte"
IDS_MUI_APPTITLE_PASTEBOARD "%s : Zwischenablage"
IDS_MUI_APPTITLE_PASTEBOARD "%s : PASTEBOARD"
IDS_MUI_UNTITLED "Kein Titel"
IDS_MUI_TITLEEXCERPT """%s"""
IDS_MUI_READONLY "(Nur Lesen)"

View File

@ -100,7 +100,7 @@ END
STRINGTABLE
BEGIN
IDS_MUI_APPTITLE_ELEVATED "%s : Elevated"
IDS_MUI_APPTITLE_PASTEBOARD "%s : Clipboard"
IDS_MUI_APPTITLE_PASTEBOARD "%s : PASTEBOARD"
IDS_MUI_UNTITLED "Untitled"
IDS_MUI_TITLEEXCERPT """%s"""
IDS_MUI_READONLY "(Read Only)"

View File

@ -100,7 +100,7 @@ END
STRINGTABLE
BEGIN
IDS_MUI_APPTITLE_ELEVATED "%s : Elevated"
IDS_MUI_APPTITLE_PASTEBOARD "%s : Clipboard"
IDS_MUI_APPTITLE_PASTEBOARD "%s : PASTEBOARD"
IDS_MUI_UNTITLED "Untitled"
IDS_MUI_TITLEEXCERPT """%s"""
IDS_MUI_READONLY "(Read Only)"

View File

@ -226,6 +226,10 @@ PasteBoardSeparator=\r\n\r\n\r\n ; two blank lines between entries
Set to `1` to prepend a `[HH:MM:SS]` timestamp to each pasted entry.
#### `PasteBoardInitialShowMs=1500`
When Notepad3 is launched with **both `/B` (clipboard monitoring) and `/I` (start minimized)**, the immediate minimize is deferred so the user can see the window populate with the one-shot auto-pasted clipboard content. The window stays visible for this many milliseconds, then minimizes (to the tray or taskbar, per `Settings.MinimizeToTray`). Range: `500``5000` ms (clamped at load time). Has no effect unless both `/B` and `/I` are passed on the command line — `/I` alone still minimizes immediately as before.
#### `NoFadeHidden=0`
Set to `1` to disable fading of hidden objects in file lists (Favorites, etc.).
@ -276,6 +280,12 @@ Managed by Notepad3 (Menu → Settings → Window → Reuse Window, **Ctrl+Shift
Whether to prompt for save when closing an untitled document that contains only whitespace.
#### `DiscardOnClosingUntitledPasteBoard=0`
Set to `1` to enable an opt-out variant of the close-modified prompt for **Untitled** documents (documents with no associated file path) **while clipboard-monitoring (PasteBoard) mode is active** — i.e. when Notepad3 was launched with `/B` or PasteBoard mode was toggled on via `Edit → Toggle Clipboard Monitoring`. With the default (`0`), or whenever PasteBoard mode is inactive, the standard Save / Discard / Cancel prompt is shown without a "Don't show this dialog again" checkbox.
When the gate matches (flag set + Untitled + PasteBoard active), closing a modified untitled document shows the same Save / Discard / Cancel prompt with a **"Don't show this dialog again"** checkbox and Discard pre-selected as the default button. If the box is checked alongside a Save or Discard answer, that choice is persisted under `[Suppressed Messages] MsgDiscardUntitled` in the INI and replays silently on subsequent close-untitled events — useful when Notepad3 is regularly used as a clipboard scratchpad. Cancel is never persisted. To re-enable the prompt, delete the `MsgDiscardUntitled` line from the `[Suppressed Messages]` section, or simply set `DiscardOnClosingUntitledPasteBoard=0` (the loader auto-clears the suppression entry on next start). Has no effect on documents that have a file path or when PasteBoard mode is not active.
#### `SciFontQuality=3`
Scintilla font rendering quality:

View File

@ -1376,6 +1376,16 @@ void LoadSettings()
Settings2.SubWrappedLineSelectOnMarginClick = IniSectionGetBool(IniSecSettings2, L"SubWrappedLineSelectOnMarginClick", false);
Settings2.DiscardOnClosingUntitledPasteBoard = IniSectionGetBool(IniSecSettings2, L"DiscardOnClosingUntitledPasteBoard", false);
if (!Settings2.DiscardOnClosingUntitledPasteBoard) {
// Drop any stale opt-out so re-enabling the feature later starts with a fresh prompt.
// Use the cache-aware IniSectionDelete (not IniFileDelete) — LoadSettings runs inside
// an OpenSettingsFile/CloseSettingsFile bracket that flushes the cache back at the end;
// a direct file write here would be overwritten. Mark dirty so the flush happens.
IniSectionDelete(Constants.SectionSuppressedMessages, Constants.SuppressKey.MsgDiscardUntitled, false);
bDirtyFlag = true;
}
int const iAnsiCPBonusSet = clampi(IniSectionGetInt(IniSecSettings2, L"LocaleAnsiCodePageAnalysisBonus", 33), 0, 100);
Settings2.LocaleAnsiCodePageAnalysisBonus = (float)iAnsiCPBonusSet / 100.0f;
@ -1470,6 +1480,7 @@ void LoadSettings()
}
Settings2.PasteBoardDebounceMs = clampi(IniSectionGetInt(IniSecSettings2, L"PasteBoardDebounceMs", 200), 0, 5000);
Settings2.PasteBoardAddTimestamp = IniSectionGetBool(IniSecSettings2, L"PasteBoardAddTimestamp", false);
Settings2.PasteBoardInitialShowMs = clampi(IniSectionGetInt(IniSecSettings2, L"PasteBoardInitialShowMs", 1500), 500, 5000);
for (int i = 0; i < COUNTOF(Settings2.CodeFontPrefPrioList); ++i) {
if (i < COUNTOF(g_CodeFontPrioList))
@ -2533,7 +2544,7 @@ void CmdSaveSettingsNow()
}
}
if (Globals.bCanSaveIniFile && SaveAllSettings(true)) {
InfoBoxLng(MB_ICONINFORMATION, L"MsgSaveSettingsInfo", IDS_MUI_SAVEDSETTINGS);
InfoBoxLng(MB_ICONINFORMATION, Constants.SuppressKey.MsgSaveSettingsInfo, IDS_MUI_SAVEDSETTINGS);
if ((dwFileAttributes != 0) && (dwFileAttributes != INVALID_FILE_ATTRIBUTES)) {
Path_SetFileAttributes(Paths.IniFile, dwFileAttributes); // reset
}

View File

@ -17,13 +17,10 @@
#include <windowsx.h>
#include <commctrl.h>
#include <process.h>
#include <shlobj.h>
#include <shellapi.h>
#include <shlwapi.h>
#include <commdlg.h>
#include <shobjidl.h>
#include <shellscalingapi.h>
#include <shlobj.h>
#include <string.h>
@ -34,7 +31,6 @@
#include "VersionEx.h"
#include "PathLib.h"
#include "Edit.h"
#include "Dlapi.h"
#include "Encoding.h"
#include "Styles.h"
@ -44,9 +40,6 @@
#include "DarkMode/DarkMode.h"
#include "tinyexprcpp/tinyexpr_cif.h"
#include "Resample.h"
#include "PathLib.h"
#include "SciCall.h"
#include "Dialogs.h"
@ -95,6 +88,44 @@ typedef struct _infbox {
bool bDisableCheckBox;
} INFOBOXLNG, *LPINFOBOXLNG;
// Map (MB_TYPEMASK | MB_DEFMASK) → control ID of the requested default button per InfoBox dialog template (IDD_MUI_INFOBOX..INFOBOX7). Returns 0 for unmapped styles (e.g. MB_FILECHANGEDNOTIFY) so the caller can fall back to the template's resource default.
static int _InfoBoxLng_GetDefaultBtnId(UINT uType)
{
UINT const btnType = uType & MB_TYPEMASK;
UINT const defBtn = uType & MB_DEFMASK;
switch (btnType) {
case MB_OK:
return IDOK;
case MB_YESNO:
return (defBtn == MB_DEFBUTTON2) ? IDNO : IDYES;
case MB_OKCANCEL:
return (defBtn == MB_DEFBUTTON2) ? IDCANCEL : IDOK;
case MB_YESNOCANCEL:
switch (defBtn) {
case MB_DEFBUTTON2: return IDNO;
case MB_DEFBUTTON3: return IDCANCEL;
default: return IDOK; // template uses IDOK for "Yes"
}
case MB_RETRYCANCEL:
return (defBtn == MB_DEFBUTTON2) ? IDCANCEL : IDRETRY;
case MB_ABORTRETRYIGNORE:
switch (defBtn) {
case MB_DEFBUTTON2: return IDRETRY;
case MB_DEFBUTTON3: return IDIGNORE;
default: return IDABORT;
}
case MB_CANCELTRYCONTINUE:
switch (defBtn) {
case MB_DEFBUTTON2: return IDRETRY; // template uses IDRETRY for "Try Again"
case MB_DEFBUTTON3: return IDCONTINUE;
default: return IDCANCEL;
}
default:
return 0;
}
}
static INT_PTR CALLBACK _InfoBoxLngDlgProc(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam)
{
static HBITMAP hIconBmp = NULL;
@ -239,6 +270,19 @@ static INT_PTR CALLBACK _InfoBoxLngDlgProc(HWND hwnd, UINT umsg, WPARAM wParam,
CenterDlgInParent(hwnd, true);
AttentionBeep(lpMsgBox->uType);
// Custom dialog templates don't honor MB_DEFBUTTON* automatically: DM_SETDEFID relocates the BS_DEFPUSHBUTTON border + Enter target
// SetFocus moves keyboard focus. Helper maps (style, defbutton) → control ID
// returns 0 for unknown styles so we fall through to the template's resource default.
int const defFocusId = _InfoBoxLng_GetDefaultBtnId(lpMsgBox->uType);
if (defFocusId) {
HWND const hDefBtn = GetDlgItem(hwnd, defFocusId);
if (hDefBtn) {
SendMessage(hwnd, DM_SETDEFID, (WPARAM)defFocusId, 0);
SetFocus(hDefBtn);
return FALSE;
}
}
}
return TRUE;
@ -302,17 +346,19 @@ CASE_WM_CTLCOLOR_SET:
case WM_COMMAND: {
LPINFOBOXLNG const lpMsgBox = (LPINFOBOXLNG)GetWindowLongPtr(hwnd, DWLP_USER);
switch (LOWORD(wParam)) {
case IDOK:
// Persistable button set (WRITE side) — must agree with InfoBoxLng() READ switch and IDC_INFOBOXCHECK ENABLE list
// divergence yields "saved but never replayed" answers.
case IDYES:
case IDNO:
case IDOK:
case IDRETRY:
case IDIGNORE:
case IDTRYAGAIN:
case IDIGNORE:
case IDCONTINUE:
if (IsButtonChecked(hwnd, IDC_INFOBOXCHECK) && StrIsNotEmpty(lpMsgBox->lpstrSetting) && Globals.bCanSaveIniFile) {
IniFileSetLong(Paths.IniFile, Constants.SectionSuppressedMessages, lpMsgBox->lpstrSetting, LOWORD(wParam));
}
//[FallThrough]
case IDNO:
//[FallThrough] - buttons to be disabled
case IDABORT:
case IDCLOSE:
case IDCANCEL:
@ -320,14 +366,14 @@ CASE_WM_CTLCOLOR_SET:
break;
case IDC_INFOBOXCHECK: {
// Persistable button set (ENABLE side) — disable only non-persistable controls
// so the user picks an answer the WRITE/READ sides round-trip.
// No WM_NEXTDLGCTL: moving focus onto a pushbutton would override DM_SETDEFID's
// visual default border. Leaving focus on the checkbox preserves it.
bool const isChecked = IsButtonChecked(hwnd, IDC_INFOBOXCHECK);
DialogEnableControl(hwnd, IDNO, !isChecked);
DialogEnableControl(hwnd, IDABORT, !isChecked);
DialogEnableControl(hwnd, IDIGNORE, !isChecked);
DialogEnableControl(hwnd, IDCONTINUE, !isChecked);
DialogEnableControl(hwnd, IDCLOSE, !isChecked);
DialogEnableControl(hwnd, IDCANCEL, !isChecked);
SendMessage(hwnd, WM_NEXTDLGCTL, 0, FALSE);
}
break;
@ -355,9 +401,15 @@ LONG InfoBoxLng(UINT uType, LPCWSTR lpstrSetting, UINT uidMsg, ...)
uType |= MB_RTLREADING;
}
// Persistable button set (READ side) — must include every value the WM_COMMAND WRITE list can store
// saved values not listed here fall into `default:` and are silently deleted on next call.
switch (iMode) {
case IDOK:
case IDYES:
case IDNO:
case IDRETRY:
case IDTRYAGAIN:
case IDIGNORE:
case IDCONTINUE:
return MAKELONG(iMode, iMode);
@ -436,7 +488,8 @@ LONG InfoBoxLng(UINT uType, LPCWSTR lpstrSetting, UINT uidMsg, ...)
msgBox.lpstrSetting = (LPWSTR)lpstrSetting;
msgBox.bDisableCheckBox = (!Globals.bCanSaveIniFile || StrIsEmpty(lpstrSetting) || (iMode < 0)) ? true : false;
int idDlg;
int idDlg = IDD_MUI_INFOBOX;
switch (uType & MB_TYPEMASK) {
case MB_OK: // one push button : OK. This is the default.
@ -1208,7 +1261,7 @@ CASE_WM_CTLCOLOR_SET:
WCHAR wchBuf2[128] = { L'\0' };
WCHAR wchVerInfo[2048] = { L'\0' };
int ResX, ResY;
int ResX = 0, ResY = 0;
GetCurrentMonitorResolution(Globals.hwndMain, &ResX, &ResY);
// --------------------------------------------------------------------
@ -1601,11 +1654,10 @@ static INT_PTR CALLBACK OpenWithDlgProc(HWND hwnd,UINT umsg,WPARAM wParam,LPARAM
case WM_SIZE: {
int dx, dy;
int dx = 0, dy = 0;
ResizeDlg_Size(hwnd,lParam,&dx,&dy);
HDWP hdwp;
hdwp = BeginDeferWindowPos(5);
HDWP hdwp = BeginDeferWindowPos(5);
hdwp = DeferCtlPos(hdwp,hwnd,IDOK,dx,dy,SWP_NOSIZE);
hdwp = DeferCtlPos(hdwp,hwnd,IDCANCEL,dx,dy,SWP_NOSIZE);
hdwp = DeferCtlPos(hdwp,hwnd,IDC_OPENWITHDIR,dx,dy,SWP_NOMOVE);
@ -1861,11 +1913,10 @@ static INT_PTR CALLBACK FavoritesDlgProc(HWND hwnd,UINT umsg,WPARAM wParam,LPARA
case WM_SIZE: {
int dx, dy;
int dx = 0, dy = 0;
ResizeDlg_Size(hwnd,lParam,&dx,&dy);
HDWP hdwp;
hdwp = BeginDeferWindowPos(5);
HDWP hdwp = BeginDeferWindowPos(5);
hdwp = DeferCtlPos(hdwp,hwnd,IDOK,dx,dy,SWP_NOSIZE);
hdwp = DeferCtlPos(hdwp,hwnd,IDCANCEL,dx,dy,SWP_NOSIZE);
hdwp = DeferCtlPos(hdwp,hwnd,IDC_FAVORITESDIR,dx,dy,SWP_NOMOVE);
@ -2074,7 +2125,7 @@ static INT_PTR CALLBACK AddToFavDlgProc(HWND hwnd, UINT umsg, WPARAM wParam, LPA
case WM_SIZE: {
int dx;
int dx = 0;
ResizeDlg_Size(hwnd, lParam, &dx, NULL);
HDWP hdwp = BeginDeferWindowPos(4);
hdwp = DeferCtlPos(hdwp, hwnd, IDOK, dx, 0, SWP_NOSIZE);
@ -2358,7 +2409,7 @@ static INT_PTR CALLBACK FileMRUDlgProc(HWND hwnd, UINT umsg, WPARAM wParam, LPAR
return FALSE;
case WM_SIZE: {
int dx, dy;
int dx = 0, dy = 0;
ResizeDlg_Size(hwnd, lParam, &dx, &dy);
HDWP hdwp = BeginDeferWindowPos(8);
hdwp = DeferCtlPos(hdwp, hwnd, IDOK, dx, dy, SWP_NOSIZE);
@ -2922,7 +2973,7 @@ CASE_WM_CTLCOLOR_SET:
switch (LOWORD(wParam)) {
case IDOK: {
BOOL fTranslated;
BOOL fTranslated = FALSE;
UINT const iNewNumber = GetDlgItemInt(hwnd, IDC_COLUMNWRAP, &fTranslated, FALSE);
if (fTranslated) {
UINT* piNumber = (UINT*)GetWindowLongPtr(hwnd, DWLP_USER);
@ -3144,7 +3195,7 @@ static INT_PTR CALLBACK LongLineSettingsDlgProc(HWND hwnd, UINT umsg, WPARAM wPa
SetDlgItemText(hwnd, IDC_MULTIEDGELINE, pszColumnList);
SendDlgItemMessage(hwnd, IDC_MULTIEDGELINE, EM_LIMITTEXT, MIDSZ_BUFFER, 0);
BOOL fTranslated;
BOOL fTranslated = FALSE;
/*UINT const iCol = */ GetDlgItemInt(hwnd, IDC_MULTIEDGELINE, &fTranslated, FALSE);
if (fTranslated) {
switch (Settings.LongLineMode) {
@ -3206,7 +3257,7 @@ CASE_WM_CTLCOLOR_SET:
switch (LOWORD(wParam)) {
case IDC_MULTIEDGELINE: {
BOOL fTranslated;
BOOL fTranslated = FALSE;
/*UINT const iCol = */ GetDlgItemInt(hwnd, IDC_MULTIEDGELINE, &fTranslated, FALSE);
if (fTranslated) {
DialogEnableControl(hwnd, IDC_SHOWEDGELINE, true);
@ -3364,7 +3415,7 @@ CASE_WM_CTLCOLOR_SET:
switch(LOWORD(wParam)) {
case IDOK: {
BOOL fTranslated1, fTranslated2;
BOOL fTranslated1 = FALSE, fTranslated2 = FALSE;
int const _iNewTabWidth = GetDlgItemInt(hwnd, IDC_TAB_WIDTH, &fTranslated1, FALSE);
int const _iNewIndentWidth = GetDlgItemInt(hwnd, IDC_INDENT_DEPTH, &fTranslated2, FALSE);
@ -3734,7 +3785,7 @@ static INT_PTR CALLBACK SelectEncodingDlgProc(HWND hwnd,UINT umsg,WPARAM wParam,
case WM_SIZE: {
int dx, dy;
int dx = 0, dy = 0;
ResizeDlg_Size(hwnd,lParam,&dx,&dy);
HDWP hdwp = BeginDeferWindowPos(3);
@ -5263,7 +5314,7 @@ void DialogAdminExe(HWND hwnd, bool bExecInstaller)
sei.nShow = SW_SHOWNORMAL;
if (bExecInstaller) {
ShellExecuteExW(&sei);
if (IsYesOkay(InfoBoxLng(MB_OKCANCEL, L"NoAdminTool", IDS_MUI_ERR_ADMINEXE))) {
if (IsYesOkay(InfoBoxLng(MB_OKCANCEL, Constants.SuppressKey.NoAdminTool, IDS_MUI_ERR_ADMINEXE))) {
sei.lpFile = VERSION_UPDATE_CHECK;
ShellExecuteExW(&sei);
}
@ -6214,7 +6265,7 @@ int Toolbar_SetButtons(HANDLE hwnd, int cmdBase, LPCWSTR lpszButtons, LPCTBBUTTO
}
p = tchButtons;
while (*p) {
int iCmd;
int iCmd = 0;
//if (swscanf_s(p, L"%i", &iCmd) == 1) {
if (StrToIntEx(p, STIF_DEFAULT, &iCmd)) {
iCmd = (iCmd == 0) ? 0 : iCmd + cmdBase - 1;
@ -6259,7 +6310,7 @@ static inline bool IsChineseTraditionalSubLang(LANGID subLang)
bool GetLocaleDefaultUIFont(LANGID lang, LPWSTR lpFaceName, WORD* wSize)
{
LPCWSTR font;
LPCWSTR font = lpFaceName;
LANGID const subLang = SUBLANGID(lang);
switch (PRIMARYLANGID(lang)) {
default:
@ -6360,7 +6411,7 @@ static inline BYTE* DialogTemplate_GetFontSizeField(const DLGTEMPLATE* pTemplate
{
bool bDialogEx = DialogTemplate_IsDialogEx(pTemplate);
WORD* pw;
WORD* pw = NULL;
if (bDialogEx) {
pw = (WORD*)((DLGTEMPLATEEX*)pTemplate + 1);

View File

@ -572,7 +572,7 @@ bool EditSetNewEncoding(HWND hwnd, cpi_enc_t iNewEncoding, bool bSupressWarning)
if (Sci_IsDocEmpty()) {
bool const doNewEncoding = (Sci_HaveUndoRedoHistory() && !bSupressWarning) ?
IsYesOkay(InfoBoxLng(MB_YESNO, L"MsgConv2", IDS_MUI_ASK_ENCODING2)) : true;
IsYesOkay(InfoBoxLng(MB_YESNO, Constants.SuppressKey.MsgConv2, IDS_MUI_ASK_ENCODING2)) : true;
if (doNewEncoding) {
return EditConvertText(hwnd, iCurrentEncoding, iNewEncoding);
@ -585,7 +585,7 @@ bool EditSetNewEncoding(HWND hwnd, cpi_enc_t iNewEncoding, bool bSupressWarning)
bSupressWarning = bIsCurANSI && bIsTargetUTF;
}
bool const doNewEncoding = (!bSupressWarning) ? IsYesOkay(InfoBoxLng(MB_YESNO, L"MsgConv1", IDS_MUI_ASK_ENCODING)) : true;
bool const doNewEncoding = (!bSupressWarning) ? IsYesOkay(InfoBoxLng(MB_YESNO, Constants.SuppressKey.MsgConv1, IDS_MUI_ASK_ENCODING)) : true;
if (doNewEncoding) {
return EditConvertText(hwnd, iCurrentEncoding, iNewEncoding);
}
@ -1301,7 +1301,7 @@ bool EditLoadFile(
WCHAR sizeWarnStr[64] = { L'\0' };
StrFormatByteSizeEx(fileSizeWarning, SFBS_FLAGS_ROUND_TO_NEAREST_DISPLAYED_DIGIT, sizeWarnStr, COUNTOF(sizeWarnStr));
Flags.bHugeFileLoadState = true;
if (!IsYesOkay(InfoBoxLng(MB_YESNO, L"MsgFileSizeWarning", IDS_MUI_WARN_LOAD_BIG_FILE, sizeStr, sizeWarnStr))) {
if (!IsYesOkay(InfoBoxLng(MB_YESNO, Constants.SuppressKey.MsgFileSizeWarning, IDS_MUI_WARN_LOAD_BIG_FILE, sizeStr, sizeWarnStr))) {
CloseHandle(hFile);
Encoding_Forced(CPI_NONE);
goto observe;
@ -1319,7 +1319,7 @@ bool EditLoadFile(
// check for unknown file/extension
status->bUnknownExt = false;
if (!Style_HasLexerForExt(hfile_pth)) {
if (!IsYesOkay(InfoBoxLng(MB_YESNO, L"MsgFileUnknownExt", IDS_MUI_WARN_UNKNOWN_EXT, Path_FindFileName(hfile_pth)))) {
if (!IsYesOkay(InfoBoxLng(MB_YESNO, Constants.SuppressKey.MsgFileUnknownExt, IDS_MUI_WARN_UNKNOWN_EXT, Path_FindFileName(hfile_pth)))) {
CloseHandle(hFile);
Encoding_Forced(CPI_NONE);
status->bUnknownExt = true;
@ -1346,7 +1346,7 @@ bool EditLoadFile(
bReadSuccess = ((readFlag & DECRYPT_FATAL_ERROR) || (readFlag & DECRYPT_FREAD_FAILED)) ? false : true;
if ((readFlag & DECRYPT_CANCELED_NO_PASS) || (readFlag & DECRYPT_WRONG_PASS)) {
bReadSuccess = IsYesOkay(InfoBoxLng(MB_OKCANCEL, L"MsgNoOrWrongPassphrase", IDS_MUI_NOPASS));
bReadSuccess = IsYesOkay(InfoBoxLng(MB_OKCANCEL, Constants.SuppressKey.MsgNoOrWrongPassphrase, IDS_MUI_NOPASS));
if (!bReadSuccess) {
Encoding_Forced(CPI_NONE);
FreeMem(lpData);
@ -1414,7 +1414,7 @@ bool EditLoadFile(
}
status->iEOLMode = Settings.DefaultEOLMode;
FreeMem(lpData);
InfoBoxLng(MB_ICONWARNING, L"MsgUTF32Unsupported", IDS_MUI_ERR_ENCODINGNA);
InfoBoxLng(MB_ICONWARNING, Constants.SuppressKey.MsgUTF32Unsupported, IDS_MUI_ERR_ENCODINGNA);
goto observe;
}
@ -1798,7 +1798,7 @@ bool EditSaveFile(
FreeMem(lpDataWide);
if (!bCancelDataLoss || IsYesOkay(InfoBoxLng(MB_OKCANCEL, L"MsgConv3", IDS_MUI_ERR_UNICODE2))) {
if (!bCancelDataLoss || IsYesOkay(InfoBoxLng(MB_OKCANCEL, Constants.SuppressKey.MsgConv3, IDS_MUI_ERR_UNICODE2))) {
SetEndOfFile(hFile);
if (cbDataConverted != 0) {
bWriteSuccess = EncryptAndWriteFile(hwnd, hFile, (BYTE *)lpData, cbDataConverted, &bytesWritten);
@ -7548,7 +7548,7 @@ bool EditFindNext(HWND hwnd, const LPEDITFINDREPLACE lpefr, bool bExtendSelectio
DocPos iPos = _FindInTarget(wchFind, sFlags, &start, &end, true, FRMOD_NORM);
if ((iPos < NOT_FOUND) && bIsRegExpr) {
InfoBoxLng(MB_ICONWARNING, L"MsgInvalidRegex", IDS_MUI_REGEX_INVALID);
InfoBoxLng(MB_ICONWARNING, Constants.SuppressKey.MsgInvalidRegex, IDS_MUI_REGEX_INVALID);
bSuppressNotFound = true;
} else if ((iPos < 0LL) && (start >= 0LL) && !bExtendSelection) {
UpdateStatusbar(false);
@ -7562,11 +7562,11 @@ bool EditFindNext(HWND hwnd, const LPEDITFINDREPLACE lpefr, bool bExtendSelectio
if ((iPos < 0LL) || (end == _start)) {
if ((iPos < -1) && bIsRegExpr) {
InfoBoxLng(MB_ICONWARNING, L"MsgInvalidRegex", IDS_MUI_REGEX_INVALID);
InfoBoxLng(MB_ICONWARNING, Constants.SuppressKey.MsgInvalidRegex, IDS_MUI_REGEX_INVALID);
bSuppressNotFound = true;
}
} else {
LONG const result = InfoBoxLng(MB_OKCANCEL, L"MsgFindWrap1", IDS_MUI_FIND_WRAPFW);
LONG const result = InfoBoxLng(MB_OKCANCEL, Constants.SuppressKey.MsgFindWrap1, IDS_MUI_FIND_WRAPFW);
if (!IsYesOkay(result)) {
iPos = NOT_FOUND;
bSuppressNotFound = true;
@ -7578,7 +7578,7 @@ bool EditFindNext(HWND hwnd, const LPEDITFINDREPLACE lpefr, bool bExtendSelectio
if (iPos < 0LL) {
if (!bSuppressNotFound) {
InfoBoxLng(MB_OK, L"MsgNotFound", IDS_MUI_NOTFOUND);
InfoBoxLng(MB_OK, Constants.SuppressKey.MsgNotFound, IDS_MUI_NOTFOUND);
}
return false;
}
@ -7649,7 +7649,7 @@ bool EditFindPrev(HWND hwnd, LPEDITFINDREPLACE lpefr, bool bExtendSelection, boo
DocPos iPos = _FindInTarget(wchFind, sFlags, &start, &end, true, FRMOD_NORM);
if ((iPos < NOT_FOUND) && bIsRegExpr) {
InfoBoxLng(MB_ICONWARNING, L"MsgInvalidRegex", IDS_MUI_REGEX_INVALID);
InfoBoxLng(MB_ICONWARNING, Constants.SuppressKey.MsgInvalidRegex, IDS_MUI_REGEX_INVALID);
bSuppressNotFound = true;
} else if ((iPos < 0LL) && (start <= iDocEndPos) && !bExtendSelection) {
UpdateStatusbar(false);
@ -7663,11 +7663,11 @@ bool EditFindPrev(HWND hwnd, LPEDITFINDREPLACE lpefr, bool bExtendSelection, boo
if ((iPos < 0LL) || (start == _start)) {
if ((iPos < NOT_FOUND) && bIsRegExpr) {
InfoBoxLng(MB_ICONWARNING, L"MsgInvalidRegex", IDS_MUI_REGEX_INVALID);
InfoBoxLng(MB_ICONWARNING, Constants.SuppressKey.MsgInvalidRegex, IDS_MUI_REGEX_INVALID);
bSuppressNotFound = true;
}
} else {
LONG const result = InfoBoxLng(MB_OKCANCEL, L"MsgFindWrap2", IDS_MUI_FIND_WRAPRE);
LONG const result = InfoBoxLng(MB_OKCANCEL, Constants.SuppressKey.MsgFindWrap2, IDS_MUI_FIND_WRAPRE);
if (!IsYesOkay(result)) {
iPos = NOT_FOUND;
bSuppressNotFound = true;
@ -7679,7 +7679,7 @@ bool EditFindPrev(HWND hwnd, LPEDITFINDREPLACE lpefr, bool bExtendSelection, boo
if (iPos < 0LL) {
if (!bSuppressNotFound) {
InfoBoxLng(MB_OK, L"MsgNotFound", IDS_MUI_NOTFOUND);
InfoBoxLng(MB_OK, Constants.SuppressKey.MsgNotFound, IDS_MUI_NOTFOUND);
}
return false;
}
@ -7906,7 +7906,7 @@ DocPosU EditReplaceAllInRange(HWND hwnd, LPEDITFINDREPLACE lpefr, DocPos iStartP
DocPos iPos = _FindInTarget(wchFind, sFlags, &start, &end, false, FRMOD_NORM);
if ((iPos < NOT_FOUND) && bIsRegExpr) {
InfoBoxLng(MB_ICONWARNING, L"MsgInvalidRegex", IDS_MUI_REGEX_INVALID);
InfoBoxLng(MB_ICONWARNING, Constants.SuppressKey.MsgInvalidRegex, IDS_MUI_REGEX_INVALID);
return 0;
}
@ -7970,9 +7970,9 @@ bool EditReplaceAll(HWND hwnd, LPEDITFINDREPLACE lpefr, bool bShowInfo)
if (bShowInfo) {
if (Globals.iReplacedOccurrences) {
InfoBoxLng(MB_OK, L"MsgReplaceCount", IDS_MUI_REPLCOUNT, wchOcc);
InfoBoxLng(MB_OK, Constants.SuppressKey.MsgReplaceCount, IDS_MUI_REPLCOUNT, wchOcc);
} else {
InfoBoxLng(MB_OK, L"MsgNotFound", IDS_MUI_NOTFOUND);
InfoBoxLng(MB_OK, Constants.SuppressKey.MsgNotFound, IDS_MUI_NOTFOUND);
}
}
@ -8011,11 +8011,11 @@ bool EditReplaceAllInSelection(HWND hwnd, LPEDITFINDREPLACE lpefr, bool bShowInf
WCHAR wchOcc[64] = { L'\0' };
StringCchPrintf(wchOcc, COUNTOF(wchOcc), DOCPOSFMTW, Globals.iReplacedOccurrences);
FormatNumberStr(wchOcc, COUNTOF(wchOcc), 0);
InfoBoxLng(MB_OK, L"MsgReplaceCount", IDS_MUI_REPLCOUNT, wchOcc);
InfoBoxLng(MB_OK, Constants.SuppressKey.MsgReplaceCount, IDS_MUI_REPLCOUNT, wchOcc);
}
}
else if (bShowInfo) {
InfoBoxLng(MB_OK, L"MsgNotFound", IDS_MUI_NOTFOUND);
InfoBoxLng(MB_OK, Constants.SuppressKey.MsgNotFound, IDS_MUI_NOTFOUND);
}
return (bool)Globals.iReplacedOccurrences;
@ -8702,7 +8702,7 @@ void EditBookMarkLineRange(HWND hwnd)
}
}
if (marker >= MARKER_NP3_BOOKMARK) {
InfoBoxLng(MB_ICONWARNING, L"OutOfOccurrenceMarkers", IDS_MUI_OUT_OFF_OCCMRK);
InfoBoxLng(MB_ICONWARNING, Constants.SuppressKey.OutOfOccurrenceMarkers, IDS_MUI_OUT_OFF_OCCMRK);
return;
}

View File

@ -87,6 +87,7 @@ unsigned grepWinLang_CountOf() {
return COUNTOF(grepWinLangFileName);
};
// -----------------------------------------------------------------------------
grepWinLng_t grepWinLangFileNamePortableApps[] = {
{ L"en-US", L"" }, // build-in language
@ -456,9 +457,8 @@ unsigned LoadLanguageResources(LPCWSTR pLocaleName) {
MUI_LanguageDLLs[iInternalLngIndex].bIsActive = true;
iLngIndex = iInternalLngIndex;
const WCHAR *const suprMsg = L"MsgPrefLanguageNotAvailable";
InfoBoxLng(MB_ICONWARNING, suprMsg, IDS_WARN_PREF_LNG_NOT_AVAIL, pLocaleName);
int const noMsg = IniFileGetLong(Paths.IniFile, Constants.SectionSuppressedMessages, suprMsg, 0);
InfoBoxLng(MB_ICONWARNING, Constants.SuppressKey.MsgPrefLanguageNotAvailable, IDS_WARN_PREF_LNG_NOT_AVAIL, pLocaleName);
int const noMsg = IniFileGetLong(Paths.IniFile, Constants.SectionSuppressedMessages, Constants.SuppressKey.MsgPrefLanguageNotAvailable, 0);
if (noMsg && Globals.bCanSaveIniFile) {
IniFileSetString(Paths.IniFile, Constants.Settings2_Section, L"PreferredLanguageLocaleName", MUI_LanguageDLLs[iInternalLngIndex].LocaleName);
}

View File

@ -30,9 +30,7 @@
#include <commdlg.h>
#include <stdio.h>
#include <string.h>
#include <process.h>
#include <vsstyle.h>
//#include <ShellScalingApi.h>
#include "PathLib.h"
#include "Edit.h"
@ -93,6 +91,33 @@ CONSTANTS_T const Constants = {
, L"Window" // Inifile Section "Window"
, L"Styles" // Inifile Section "Styles"
, L"Suppressed Messages" // Inifile Section "SuppressedMessages"
, { // SuppressKey — keys under [Suppressed Messages]
L"AllowClearUndoHistory"
, L"InfoInstanceExist"
, L"MsgConv1"
, L"MsgConv2"
, L"MsgConv3"
, L"MsgDiscardUntitled"
, L"MsgFileSizeWarning"
, L"MsgFileUnknownExt"
, L"MsgFindWrap1"
, L"MsgFindWrap2"
, L"MsgInvalidRegex"
, L"MsgNoOrWrongPassphrase"
, L"MsgNotFound"
, L"MsgPrefLanguageNotAvailable"
, L"MsgReplaceCount"
, L"MsgResetScheme"
, L"MsgSaveSettingsInfo"
, L"MsgStickyWinPos"
, L"MsgUTF32Unsupported"
, L"NoAdminTool"
, L"NotSuitableToolbarDim"
, L"OutOfOccurrenceMarkers"
, L"PreserveFileModTime"
, L"QuietKeepReadonlyLock"
, L"ReloadExSavedCfg"
}
};
@ -453,7 +478,7 @@ static void CALLBACK MQ_ExecuteNext(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWOR
UNREFERENCED_PARAMETER(idEvent); // must be IDT_TIMER_MRKALL
UNREFERENCED_PARAMETER(dwTime); // This is the value returned by the GetTickCount() function
CmdMessageQueue_t* pmqc;
CmdMessageQueue_t* pmqc = NULL;
DL_FOREACH(MessageQueue, pmqc) {
if (pmqc->delay >= 0) {
--(pmqc->delay); // count down
@ -860,7 +885,7 @@ static void _CleanUpResources(const HWND hwnd, bool bIsInitialized)
}
CmdMessageQueue_t* pmqc = NULL;
CmdMessageQueue_t* dummy;
CmdMessageQueue_t* dummy = NULL;
DL_FOREACH_SAFE(MessageQueue, pmqc, dummy) {
DL_DELETE(MessageQueue, pmqc);
FreeMem(pmqc);
@ -1824,6 +1849,35 @@ bool InitWndClass(const HINSTANCE hInstance, LPCWSTR lpszWndClassName, LPCWSTR l
#endif
//=============================================================================
//
// _StartupMinimizeMainWnd() / _DeferMinimizeTimerProc()
// Hoisted from InitInstance() so the same minimize sequence runs either immediately
// or after the deferred-minimize timer fires (used for the /B + /I startup combo).
//
static void _StartupMinimizeMainWnd(HWND hwndMain)
{
SetWindowPos(hwndMain, Settings.AlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
if (!Settings.ShowTitlebar) {
SetWindowLong(hwndMain, GWL_STYLE, GetWindowLong(hwndMain, GWL_STYLE) & ~WS_CAPTION);
}
if (Settings.MinimizeToTray) {
MinimizeWndToTray(hwndMain);
}
else {
MinimizeWndToTaskbar(hwndMain);
}
}
static VOID CALLBACK _DeferMinimizeTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{
UNREFERENCED_PARAMETER(uMsg);
UNREFERENCED_PARAMETER(dwTime);
KillTimer(hwnd, idEvent); // one-shot
_StartupMinimizeMainWnd(hwnd);
}
//=============================================================================
//
// InitInstance() - DarkMode already initialized !
@ -1905,15 +1959,21 @@ HWND InitInstance(const HINSTANCE hInstance, int nCmdShow)
// Determine if starting minimized/tray (don't show window early in that case)
bool const bStartMinimized = s_flagStartAsTrayIcon || (nCmdShow == SW_MINIMIZE) || (nCmdShow == SW_SHOWMINIMIZED);
// /B + /I together: show the window long enough for the one-shot auto-paste to land,
// then minimize via timer (fired below after PasteBoard_Start). Captures s_flagPasteBoard
// before the PasteBoard activation block clears it.
bool const bDeferMinimizeForPasteBoard = bStartMinimized && s_flagPasteBoard;
// Show window frame early for faster perceived startup — the user sees
// the window (with initial toolbar from WM_CREATE) while we re-create bars
if (!bStartMinimized) {
// the window (with initial toolbar from WM_CREATE) while we re-create bars.
// For the /B + /I deferred-minimize case, force SW_SHOWNORMAL: nCmdShow could be
// SW_SHOWMINIMIZED (shortcut "Start minimized") which would defeat the purpose.
if (!bStartMinimized || bDeferMinimizeForPasteBoard) {
if (!Settings.ShowTitlebar) {
SetWindowLong(hwndMain, GWL_STYLE, GetWindowLong(hwndMain, GWL_STYLE) & ~WS_CAPTION);
}
SetWindowPos(hwndMain, Settings.AlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
ShowWindow(hwndMain, nCmdShow);
ShowWindow(hwndMain, bDeferMinimizeForPasteBoard ? SW_SHOWNORMAL : nCmdShow);
UpdateWindow(hwndMain);
}
@ -1924,7 +1984,7 @@ HWND InitInstance(const HINSTANCE hInstance, int nCmdShow)
// Force layout recalculation after toolbar/statusbar re-creation
// (early ShowWindow already triggered WM_SIZE with old child windows)
if (!bStartMinimized) {
if (!bStartMinimized || bDeferMinimizeForPasteBoard) {
RECT rc;
GetClientRect(hwndMain, &rc);
SendMessage(hwndMain, WM_SIZE, SIZE_RESTORED, MAKELPARAM(rc.right, rc.bottom));
@ -1985,21 +2045,13 @@ HWND InitInstance(const HINSTANCE hInstance, int nCmdShow)
ShowWindowAsync(s_hwndEditFrame, SW_SHOWDEFAULT);
ShowWindowAsync(Globals.hwndEdit, SW_SHOWDEFAULT);
if (bStartMinimized) {
if (bStartMinimized && !bDeferMinimizeForPasteBoard) {
//~SnapToWinInfoPos(hwndMain, g_IniWinInfo, SCR_NORMAL, SW_HIDE);
SetWindowPos(hwndMain, Settings.AlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
if (!Settings.ShowTitlebar) {
SetWindowLong(hwndMain, GWL_STYLE, GetWindowLong(hwndMain, GWL_STYLE) & ~WS_CAPTION);
}
if (Settings.MinimizeToTray) {
MinimizeWndToTray(hwndMain);
}
else {
MinimizeWndToTaskbar(hwndMain);
}
_StartupMinimizeMainWnd(hwndMain);
}
else {
// Window was already shown above; ensure children are painted
// Either not minimizing, or deferring minimize until /B auto-paste lands —
// the window must paint normally so the user sees the pasted content briefly.
UpdateWindow(hwndMain);
}
@ -2161,6 +2213,12 @@ HWND InitInstance(const HINSTANCE hInstance, int nCmdShow)
}
}
// /B + /I: arm the deferred-minimize timer now that PasteBoard is started.
// PasteBoardInitialShowMs is clamped to 500..5000 at load time.
if (bDeferMinimizeForPasteBoard) {
SetTimer(Globals.hwndMain, ID_DEFERMINIMIZETIMER, (UINT)Settings2.PasteBoardInitialShowMs, _DeferMinimizeTimerProc);
}
// check if a lexer was specified from the command line
if (s_flagLexerSpecified) {
if (s_lpSchemeArg) {
@ -4163,7 +4221,7 @@ LRESULT MsgInitMenu(HWND hwnd, WPARAM wParam, LPARAM lParam)
EnableCmd(hmenu, IDM_LINEENDINGS_LF, !ro);
EnableCmd(hmenu, IDM_LINEENDINGS_CR, !ro);
int i;
int i = 0;
if (Encoding_IsUNICODE_REVERSE(Encoding_GetCurrent())) {
i = IDM_ENCODING_UNICODEREV;
@ -4592,7 +4650,7 @@ static void _ApplyChangeHistoryMode()
int const iChgHist = SciCall_GetChangeHistory();
if (iChgHist == Settings.ChangeHistoryMode) { return; }
if ((!iChgHist && Settings.ChangeHistoryMode) || !Settings.ChangeHistoryMode) {
if (IsYesOkay(InfoBoxLng(MB_YESNO | MB_ICONWARNING, L"AllowClearUndoHistory", IDS_MUI_ASK_CLEAR_UNDO))) {
if (IsYesOkay(InfoBoxLng(MB_YESNO | MB_ICONWARNING, Constants.SuppressKey.AllowClearUndoHistory, IDS_MUI_ASK_CLEAR_UNDO))) {
UndoRedoReset();
}
else {
@ -4673,7 +4731,7 @@ static bool _HandleFileCommands(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lPar
case IDM_FILE_PRESERVE_FILEMODTIME: {
if (!Flags.bPreserveFileModTime) {
InfoBoxLng(MB_OK, L"PreserveFileModTime", IDS_MUI_INF_PRSVFILEMODTM);
InfoBoxLng(MB_OK, Constants.SuppressKey.PreserveFileModTime, IDS_MUI_INF_PRSVFILEMODTM);
}
Flags.bPreserveFileModTime = true;
FileSave(FSF_SaveAlways);
@ -6408,7 +6466,7 @@ static bool _HandleViewAndSettingsCommands(HWND hwnd, UINT umsg, WPARAM wParam,
break;
case IDM_VIEW_CHGHIST_CLEAR_UNDOREDO:
if (IsYesOkay(InfoBoxLng(MB_YESNO | MB_ICONWARNING, L"AllowClearUndoHistory", IDS_MUI_ASK_CLEAR_UNDO))) {
if (IsYesOkay(InfoBoxLng(MB_YESNO | MB_ICONWARNING, Constants.SuppressKey.AllowClearUndoHistory, IDS_MUI_ASK_CLEAR_UNDO))) {
UndoRedoReset();
UpdateToolbar();
UpdateMargins(true);
@ -6566,7 +6624,7 @@ static bool _HandleViewAndSettingsCommands(HWND hwnd, UINT umsg, WPARAM wParam,
Flags.bStickyWindowPosition = !Flags.bStickyWindowPosition; // toggle
if (Flags.bStickyWindowPosition) {
InfoBoxLng(MB_OK, L"MsgStickyWinPos", IDS_MUI_STICKYWINPOS);
InfoBoxLng(MB_OK, Constants.SuppressKey.MsgStickyWinPos, IDS_MUI_STICKYWINPOS);
}
if (OpenSettingsFile("IDM_VIEW_STICKYWINPOS")) {
@ -6685,7 +6743,7 @@ static bool _HandleViewAndSettingsCommands(HWND hwnd, UINT umsg, WPARAM wParam,
case IDM_VIEW_WIN_DARK_MODE: {
if (!IsYesOkay(InfoBoxLng(MB_OKCANCEL | MB_ICONWARNING, L"MsgResetScheme", IDS_MUI_WARN_STYLE_RESET))) {
if (!IsYesOkay(InfoBoxLng(MB_OKCANCEL | MB_ICONWARNING, Constants.SuppressKey.MsgResetScheme, IDS_MUI_WARN_STYLE_RESET))) {
break;
}
@ -7590,7 +7648,7 @@ LRESULT MsgCommand(HWND hwnd, UINT umsg, WPARAM wParam, LPARAM lParam)
bool const bIsThemesMenuCmd = ((iLoWParam >= IDM_THEMES_FACTORY_RESET) && (iLoWParam < (int)(IDM_THEMES_FACTORY_RESET + ThemeItems_CountOf())));
if (bIsThemesMenuCmd) {
if (iLoWParam == IDM_THEMES_FACTORY_RESET) {
if (!IsYesOkay(InfoBoxLng(MB_OKCANCEL | MB_ICONWARNING, L"MsgResetScheme", IDS_MUI_WARN_STYLE_RESET))) {
if (!IsYesOkay(InfoBoxLng(MB_OKCANCEL | MB_ICONWARNING, Constants.SuppressKey.MsgResetScheme, IDS_MUI_WARN_STYLE_RESET))) {
return FALSE;
}
}
@ -8813,7 +8871,7 @@ inline static LRESULT _MsgNotifyLean(const SCNotification* const scn, bool* bMod
EditToggleView(Globals.hwndEdit);
}
else {
if (!FileWatching.MonitoringLog && !IsYesOkay(InfoBoxLng(MB_YESNO | MB_ICONINFORMATION, L"QuietKeepReadonlyLock", IDS_MUI_DOCUMENT_READONLY))) {
if (!FileWatching.MonitoringLog && !IsYesOkay(InfoBoxLng(MB_YESNO | MB_ICONINFORMATION, Constants.SuppressKey.QuietKeepReadonlyLock, IDS_MUI_DOCUMENT_READONLY))) {
SendWMCommand(Globals.hwndMain, IDM_VIEW_READONLY);
}
else {
@ -10938,7 +10996,7 @@ bool FileIO(bool fLoad, const HPATHL hfile_pth, EditFileIOStatus* status,
SciCall_SetReadOnly(Settings.DocReadOnlyMode || FileWatching.MonitoringLog);
}
else {
int idx;
int idx = 0;
if (MRU_FindPath(Globals.pFileMRU, hfile_pth, &idx)) {
Globals.pFileMRU->iEncoding[idx] = status->iEncoding;
Globals.pFileMRU->iCaretPos[idx] = (Settings.PreserveCaretPos ? SciCall_GetCurrentPos() : -1);
@ -11111,7 +11169,7 @@ bool FileLoad(const HPATHL hfile_pth, const FileLoadFlags fLoadFlags, const DocP
HWND hwnd = NULL;
if (FindOtherInstance(&hwnd, hopen_file)) {
if (!s_bInitAppDone || IsYesOkay(InfoBoxLng(MB_YESNO | MB_ICONQUESTION, L"InfoInstanceExist", IDS_MUI_ASK_INSTANCE_EXISTS))) {
if (!s_bInitAppDone || IsYesOkay(InfoBoxLng(MB_YESNO | MB_ICONQUESTION, Constants.SuppressKey.InfoInstanceExist, IDS_MUI_ASK_INSTANCE_EXISTS))) {
if (IsIconic(hwnd)) {
ShowWindowAsync(hwnd, SW_RESTORE);
}
@ -11176,7 +11234,7 @@ bool FileLoad(const HPATHL hfile_pth, const FileLoadFlags fLoadFlags, const DocP
}
}
else {
int idx;
int idx = 0;
if (!bReloadFile && MRU_FindPath(Globals.pFileMRU, hopen_file, &idx)) {
fioStatus.iEncoding = Globals.pFileMRU->iEncoding[idx];
if (Encoding_IsValid(fioStatus.iEncoding)) {
@ -11586,9 +11644,11 @@ bool FileSave(FileSaveFlags fSaveFlags)
GetLngString(IDS_MUI_UNTITLED, wchFileName, COUNTOF(wchFileName));
Path_GetDisplayName(wchFileName, COUNTOF(wchFileName), Paths.CurrentFile, NULL, false);
INT_PTR const answer = InfoBoxLng(MB_YESNOCANCEL | MB_ICONWARNING, NULL, IDS_MUI_ASK_SAVE, wchFileName);
switch (answer)
bool const bDiscardOptOut = Settings2.DiscardOnClosingUntitledPasteBoard && Path_IsEmpty(Paths.CurrentFile) && IsPasteBoardActive();
UINT const uMsgType = MB_YESNOCANCEL | MB_ICONWARNING | (bDiscardOptOut ? MB_DEFBUTTON2 : 0L);
LPCWSTR const lpSuppressKey = bDiscardOptOut ? Constants.SuppressKey.MsgDiscardUntitled : NULL;
INT_PTR const answer = InfoBoxLng(uMsgType, lpSuppressKey, IDS_MUI_ASK_SAVE, wchFileName);
switch (LOWORD(answer)) // InfoBoxLng packs suppression-mode in HIWORD; LOWORD holds the actual button ID
{
case IDCANCEL:
return false;
@ -11693,7 +11753,7 @@ bool FileSave(FileSaveFlags fSaveFlags)
WCHAR tch[256] = { L'\0' };
if (Settings.SaveSettings) { LoadLngStringW(IDS_MUI_RELOADCFGSEX, tch, COUNTOF(tch)); }
UINT const typ = Settings.SaveSettings ? (MB_YESNO | MB_ICONWARNING) : (MB_YESNO | MB_ICONINFORMATION);
LONG const answer = InfoBoxLng(typ, L"ReloadExSavedCfg", IDS_MUI_RELOADSETTINGS, tch);
LONG const answer = InfoBoxLng(typ, Constants.SuppressKey.ReloadExSavedCfg, IDS_MUI_RELOADSETTINGS, tch);
if (IsYesOkay(answer)) {
///~SaveAllSettings(true); ~ already saved (CurrentFile)
DialogNewWindow(Globals.hwndMain, true, Paths.CurrentFile, NULL);

View File

@ -70,6 +70,7 @@ np3params, *LPnp3params;
#define ID_LOGROTATETIMER (0xA003) // Log Rotation Retry
#define ID_AUTOSCROLLTIMER (0xA004) // Middle-Click Auto-Scroll
#define ID_ATOMICSAVETIMER (0xA005) // Atomic Save Detection
#define ID_DEFERMINIMIZETIMER (0xA006) // Deferred minimize on /B + /I startup
//==== Reuse Window Lock Timeout ==============================================

View File

@ -53,7 +53,7 @@ HBITMAP NP3Util_LoadBitmapFile(const HPATHL hpath)
bDimOK = (bmp.bmWidth >= (height * NUMTOOLBITMAPS));
}
if (!bDimOK) {
InfoBoxLng(MB_ICONWARNING, L"NotSuitableToolbarDim", IDS_MUI_ERR_BITMAP, Path_Get(hpath),
InfoBoxLng(MB_ICONWARNING, Constants.SuppressKey.NotSuitableToolbarDim, IDS_MUI_ERR_BITMAP, Path_Get(hpath),
(height * NUMTOOLBITMAPS), height, NUMTOOLBITMAPS);
}
}

View File

@ -478,6 +478,36 @@ typedef struct CONSTANTS_T {
const WCHAR* const Styles_Section;
const WCHAR* const SectionSuppressedMessages;
// Keys under [Suppressed Messages] — pass to InfoBoxLng() / IniFile{Get,Set,Delete}Long().
// Add a field here when introducing a new suppressible dialog; never inline a literal at the call site.
struct {
const WCHAR* const AllowClearUndoHistory;
const WCHAR* const InfoInstanceExist;
const WCHAR* const MsgConv1;
const WCHAR* const MsgConv2;
const WCHAR* const MsgConv3;
const WCHAR* const MsgDiscardUntitled;
const WCHAR* const MsgFileSizeWarning;
const WCHAR* const MsgFileUnknownExt;
const WCHAR* const MsgFindWrap1;
const WCHAR* const MsgFindWrap2;
const WCHAR* const MsgInvalidRegex;
const WCHAR* const MsgNoOrWrongPassphrase;
const WCHAR* const MsgNotFound;
const WCHAR* const MsgPrefLanguageNotAvailable;
const WCHAR* const MsgReplaceCount;
const WCHAR* const MsgResetScheme;
const WCHAR* const MsgSaveSettingsInfo;
const WCHAR* const MsgStickyWinPos;
const WCHAR* const MsgUTF32Unsupported;
const WCHAR* const NoAdminTool;
const WCHAR* const NotSuitableToolbarDim;
const WCHAR* const OutOfOccurrenceMarkers;
const WCHAR* const PreserveFileModTime;
const WCHAR* const QuietKeepReadonlyLock;
const WCHAR* const ReloadExSavedCfg;
} SuppressKey;
} CONSTANTS_T, *PCONSTANTS_T;
extern CONSTANTS_T const Constants;
@ -792,6 +822,7 @@ typedef struct SETTINGS2_T {
bool SubWrappedLineSelectOnMarginClick;
bool LexerSQLNumberSignAsComment;
bool AtomicFileSave;
bool DiscardOnClosingUntitledPasteBoard;
int ExitOnESCSkipLevel;
int ZoomTooltipTimeout;
int WrapAroundTooltipTimeout;
@ -847,6 +878,7 @@ typedef struct SETTINGS2_T {
WCHAR PasteBoardSeparator[MICRO_BUFFER];
int PasteBoardDebounceMs;
bool PasteBoardAddTimestamp;
int PasteBoardInitialShowMs;
const WCHAR* CodeFontPrefPrioList[MICRO_BUFFER];
const WCHAR* TextFontPrefPrioList[MICRO_BUFFER];