diff --git a/src/Dialogs.c b/src/Dialogs.c index 9e57e2265..1a3a18a1e 100644 --- a/src/Dialogs.c +++ b/src/Dialogs.c @@ -4829,8 +4829,9 @@ void AppendAdditionalTitleInfo(LPCWSTR lpszAddTitleInfo) { StringCchCat(s_wchAdditionalTitleInfo, COUNTOF(s_wchAdditionalTitleInfo), lpszAddTitleInfo); } -static const WCHAR *pszSep = L" - "; -static const WCHAR *pszMod = L"* "; +static const WCHAR *pszFChg = L"@ "; +static const WCHAR *pszMod = L"* "; +static const WCHAR *pszSep = L" - "; static WCHAR s_wchCachedFile[MAX_PATH] = { L'\0' }; static WCHAR s_wchCachedDisplayName[MAX_PATH] = { L'\0' }; @@ -4838,7 +4839,7 @@ static WCHAR s_wchCachedDisplayName[MAX_PATH] = { L'\0' }; void SetWindowTitle(HWND hwnd, LPCWSTR lpszFile, int iFormat, bool bPasteBoard, bool bIsElevated, bool bModified, - bool bFileLocked, bool bReadOnly, LPCWSTR lpszExcerpt) { + bool bFileLocked, bool bFileChanged, bool bReadOnly, LPCWSTR lpszExcerpt) { if (s_bFreezeAppTitle) { return; @@ -4861,16 +4862,22 @@ void SetWindowTitle(HWND hwnd, LPCWSTR lpszFile, int iFormat, WCHAR szTitle[MIDSZ_BUFFER] = { L'\0' }; + if (bFileChanged) { + StringCchCat(szTitle, COUNTOF(szTitle), pszFChg); + } if (bModified) { StringCchCat(szTitle, COUNTOF(szTitle), pszMod); } if (StrIsNotEmpty(lpszExcerpt)) { + WCHAR szExcrptFmt[32] = { L'\0' }; WCHAR szExcrptQuot[SMALL_BUFFER] = { L'\0' }; GetLngString(IDS_MUI_TITLEEXCERPT, szExcrptFmt, COUNTOF(szExcrptFmt)); StringCchPrintf(szExcrptQuot, COUNTOF(szExcrptQuot), szExcrptFmt, lpszExcerpt); StringCchCat(szTitle, COUNTOF(szTitle), szExcrptQuot); + } else if (StrIsNotEmpty(lpszFile)) { + if ((iFormat < 2) && !PathIsRoot(lpszFile)) { if (StringCchCompareN(s_wchCachedFile, COUNTOF(s_wchCachedFile), lpszFile, MAX_PATH) != 0) { StringCchCopy(s_wchCachedFile, COUNTOF(s_wchCachedFile), lpszFile); diff --git a/src/Dialogs.h b/src/Dialogs.h index 0015e8a8f..1ca98fffe 100644 --- a/src/Dialogs.h +++ b/src/Dialogs.h @@ -81,8 +81,8 @@ LONG InfoBoxLng(UINT uType, LPCWSTR lpstrSetting, UINT uidMsg, ...); #define INFOBOX_MODE(_R_) HIWORD(_R_) void SetWindowTitle(HWND hwnd, LPCWSTR lpszFile, int iFormat, - bool bPasteBoard, bool bIsElevated, bool bModified, - bool bFileLocked, bool bReadOnly, LPCWSTR lpszExcerpt); + bool bPasteBoard, bool bIsElevated, bool bModified, + bool bFileLocked, bool bFileChanged, bool bReadOnly, LPCWSTR lpszExcerpt); void SetAdditionalTitleInfo(LPCWSTR lpszAddTitleInfo); void AppendAdditionalTitleInfo(LPCWSTR lpszAddTitleInfo); void SetWindowTransparentMode(HWND hwnd, bool bTransparentMode, int iOpacityLevel); diff --git a/src/Notepad3.c b/src/Notepad3.c index 953ff5be1..c71b2d58a 100644 --- a/src/Notepad3.c +++ b/src/Notepad3.c @@ -534,6 +534,49 @@ static void CALLBACK MQ_ExecuteNext(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWOR } +//============================================================================= +// +// HasCurrentFileChanged +// + +static WIN32_FIND_DATA s_fdCurFile = { 0 }; +static HANDLE s_hEventFileChangedExt = INVALID_HANDLE_VALUE; + +static inline bool HasCurrentFileChanged() { + + if (StrIsEmpty(Paths.CurrentFile)) { + return false; + } + WIN32_FIND_DATA fdUpdated = { 0 }; + if (!GetFileAttributesEx(Paths.CurrentFile, GetFileExInfoStandard, &fdUpdated)) { + SetEvent(s_hEventFileChangedExt); + return true; // The current file has been removed + } + bool const changed = (s_fdCurFile.nFileSizeLow != fdUpdated.nFileSizeLow) || (s_fdCurFile.nFileSizeHigh != fdUpdated.nFileSizeHigh) + //~|| (CompareFileTime(&s_fdCurFile.ftLastWriteTime, &fdUpdated.ftLastWriteTime) != 0) + || (s_fdCurFile.ftLastWriteTime.dwLowDateTime != fdUpdated.ftLastWriteTime.dwLowDateTime) + || (s_fdCurFile.ftLastWriteTime.dwHighDateTime != fdUpdated.ftLastWriteTime.dwHighDateTime); + if (changed) { + SetEvent(s_hEventFileChangedExt); + } + return changed; +} + +static inline void ResetFileObservationData(const bool bResetEvt) { + if (bResetEvt) { + ResetEvent(s_hEventFileChangedExt); + } + if (StrIsNotEmpty(Paths.CurrentFile)) { + if (!GetFileAttributesEx(Paths.CurrentFile, GetFileExInfoStandard, &s_fdCurFile)) { + ZeroMemory(&s_fdCurFile, sizeof(WIN32_FIND_DATA)); + } + } +} + +static inline bool IsFileChangedFlagSet() { + return (WaitForSingleObject(s_hEventFileChangedExt, 0) != WAIT_TIMEOUT); +} + //============================================================================= // // InvalidateStyleRedraw @@ -579,14 +622,14 @@ static void _UpdateToolbarDelayed(); // static bool s_DocNeedSaving = false; // dirty-flag -static void SetSaveNeeded() +static inline void SetSaveNeeded() { if (!s_DocNeedSaving) { s_DocNeedSaving = true; + HasCurrentFileChanged(); + UpdateToolbar(); UpdateTitleBar(Globals.hwndMain); } - UpdateToolbar(); - if (IsWindow(Globals.hwndDlgFindReplace)) { PostWMCommand(Globals.hwndDlgFindReplace, IDC_DOC_MODIFIED); } @@ -604,8 +647,8 @@ void SetSavePoint() inline static bool GetDocModified() { - if (SciCall_GetModify() && !s_DocNeedSaving) { - SetSaveNeeded(); + if ((SciCall_GetModify() && !s_DocNeedSaving)) { + SetSaveNeeded(); } return s_DocNeedSaving; } @@ -728,6 +771,11 @@ static void _CleanUpResources(const HWND hwnd, bool bIsInitialized) UndoRedoSelectionUTArray = NULL; } + if (IS_VALID_HANDLE(s_hEventFileChangedExt)) { + CloseHandle(s_hEventFileChangedExt); + s_hEventFileChangedExt = INVALID_HANDLE_VALUE; + } + // ------------------------------- // Save Settings is done elsewhere // ------------------------------- @@ -1369,8 +1417,8 @@ HWND InitInstance(const HINSTANCE hInstance, LPCWSTR pszCmdLine, int nCmdShow) SetDialogIconNP3(Globals.hwndMain); InitWindowCommon(Globals.hwndMain, true); - // manual reset und initially not signaled (TRUE , FALSE) - // s_hEvent = CreateEvent(NULL, TRUE, TRUE, NULL); + // manual (no automatic) reset & initial state: not signaled (TRUE, FALSE) + s_hEventFileChangedExt = CreateEvent(NULL, TRUE, FALSE, NULL); if (Settings.TransparentMode) { SetWindowTransparentMode(Globals.hwndMain, true, Settings2.OpacityLevel); @@ -8478,7 +8526,7 @@ static void _UpdateToolbarDelayed() } EnableTool(Globals.hwndToolbar, IDT_FILE_ADDTOFAV, StrIsNotEmpty(Paths.CurrentFile)); - EnableTool(Globals.hwndToolbar, IDT_FILE_SAVE, GetDocModified() /*&& !bReadOnly*/); + EnableTool(Globals.hwndToolbar, IDT_FILE_SAVE, GetDocModified() || IsFileChangedFlagSet() /*&& !bReadOnly*/); EnableTool(Globals.hwndToolbar, IDT_FILE_RECENT, (MRU_Count(Globals.pFileMRU) > 0)); CheckTool(Globals.hwndToolbar, IDT_VIEW_WORDWRAP, Globals.fvCurFile.bWordWrap); @@ -9268,11 +9316,12 @@ void UpdateSaveSettingsCmds() void UpdateTitleBar(const HWND hwnd) { if (hwnd == Globals.hwndMain) { + bool const bFileLocked = (FileWatching.FileWatchingMode == FWM_EXCLUSIVELOCK); SetWindowTitle(Globals.hwndMain, Paths.CurrentFile, Settings.PathNameFormat, - s_flagPasteBoard, s_bIsProcessElevated, GetDocModified(), - bFileLocked, s_bFileReadOnly, s_wchTitleExcerpt); + s_flagPasteBoard, s_bIsProcessElevated, GetDocModified(), + bFileLocked, IsFileChangedFlagSet(), s_bFileReadOnly, s_wchTitleExcerpt); } PostMessage(hwnd, WM_NCACTIVATE, FALSE, -1); // (!) PostMessage(hwnd, WM_NCACTIVATE, TRUE, 0); @@ -9869,6 +9918,7 @@ bool FileLoad(LPCWSTR lpszFile, bool bDontSave, bool bNew, bool bReload, if (SciCall_GetZoom() != 100) { ShowZoomCallTip(); } + ResetFileObservationData(true); return true; } @@ -10078,6 +10128,10 @@ bool FileLoad(LPCWSTR lpszFile, bool bDontSave, bool bNew, bool bReload, Flags.bHugeFileLoadState = false; // reset } + if (fSuccess) { + ResetFileObservationData(true); + } + UpdateTitleBar(Globals.hwndMain); UpdateToolbar(); UpdateMarginWidth(true); @@ -10113,44 +10167,45 @@ bool FileRevert(LPCWSTR szFileName, bool bIgnoreCmdLnEnc) WCHAR tchFileName2[MAX_PATH] = { L'\0' }; StringCchCopyW(tchFileName2, COUNTOF(tchFileName2), szFileName); - //InstallFileWatching(false); + //~InstallFileWatching(false); bool const result = FileLoad(tchFileName2, true, false, true, Settings.SkipUnicodeDetection, Settings.SkipANSICodePageDetection, false); - //InstallFileWatching(true); + //~InstallFileWatching(true); - if (!result) { - return false; - } + if (result) { - if (FileWatching.FileWatchingMode == FWM_AUTORELOAD) { - if (bIsAtDocEnd || FileWatching.MonitoringLog) { - bPreserveView = false; - SciCall_DocumentEnd(); - EditScrollSelectionToView(); + if (FileWatching.FileWatchingMode == FWM_AUTORELOAD) { + if (bIsAtDocEnd || FileWatching.MonitoringLog) { + bPreserveView = false; + SciCall_DocumentEnd(); + EditScrollSelectionToView(); + } } - } - if (SciCall_GetTextLength() >= 4) { - char tch[5] = { '\0','\0','\0','\0','\0' }; - SciCall_GetText(COUNTOF(tch), tch); - if (StringCchCompareXA(tch, ".LOG") == 0) { - SciCall_ClearSelections(); - bPreserveView = false; - SciCall_DocumentEnd(); - EditScrollSelectionToView(); + if (SciCall_GetTextLength() >= 4) { + char tch[5] = { '\0', '\0', '\0', '\0', '\0' }; + SciCall_GetText(COUNTOF(tch), tch); + if (StringCchCompareXA(tch, ".LOG") == 0) { + SciCall_ClearSelections(); + bPreserveView = false; + SciCall_DocumentEnd(); + EditScrollSelectionToView(); + } + } + + if (bPreserveView) { + SciCall_SetYCaretPolicy(s_iCaretPolicyV | CARET_JUMPS, Settings2.CurrentLineVerticalSlop); + EditJumpTo(curLineNum + 1, 0); + SciCall_SetYCaretPolicy(s_iCaretPolicyV, Settings2.CurrentLineVerticalSlop); } } SetSavePoint(); UpdateMarginWidth(true); UpdateStatusbar(true); + UpdateToolbar(); + UpdateTitleBar(Globals.hwndMain); - if (bPreserveView) { - SciCall_SetYCaretPolicy(s_iCaretPolicyV | CARET_JUMPS, Settings2.CurrentLineVerticalSlop); - EditJumpTo(curLineNum + 1, 0); - SciCall_SetYCaretPolicy(s_iCaretPolicyV, Settings2.CurrentLineVerticalSlop); - } - - return true; + return result; } @@ -10301,7 +10356,7 @@ bool FileSave(bool bSaveAlways, bool bAsk, bool bSaveAs, bool bSaveCopy, bool bP #endif - if (!bSaveAlways && (!GetDocModified() || bIsEmptyNewFile) && !bSaveAs) { + if (!bSaveAlways && (!GetDocModified() || IsFileChangedFlagSet() || bIsEmptyNewFile) && !bSaveAs) { int idx; if (MRU_FindFile(Globals.pFileMRU, Paths.CurrentFile, &idx)) { Globals.pFileMRU->iEncoding[idx] = Encoding_GetCurrent(); @@ -10314,6 +10369,7 @@ bool FileSave(bool bSaveAlways, bool bAsk, bool bSaveAs, bool bSaveCopy, bool bP } Globals.pFileMRU->pszBookMarks[idx] = StrDup(wchBookMarks); } + ResetFileObservationData(true); return true; } @@ -10466,6 +10522,9 @@ bool FileSave(bool bSaveAlways, bool bAsk, bool bSaveAs, bool bSaveCopy, bool bP } } } + if (fSuccess) { + ResetFileObservationData(true); + } return fSuccess; } @@ -11032,7 +11091,6 @@ void ShowNotifyIcon(HWND hwnd,bool bAdd) // // SetNotifyIconTitle() // -// void SetNotifyIconTitle(HWND hwnd) { NOTIFYICONDATA nid = { sizeof(NOTIFYICONDATA) }; @@ -11052,11 +11110,14 @@ void SetNotifyIconTitle(HWND hwnd) } else { GetLngString(IDS_MUI_UNTITLED, tchTitle, COUNTOF(tchTitle) - 4); } - if (GetDocModified()) { - StringCchCopy(nid.szTip, COUNTOF(nid.szTip), L"* "); + if (IsFileChangedFlagSet()) { + StringCchCopy(nid.szTip, COUNTOF(nid.szTip), L"@ "); } else { StringCchCopy(nid.szTip, COUNTOF(nid.szTip), L""); } + if (GetDocModified()) { + StringCchCat(nid.szTip, COUNTOF(nid.szTip), L"* "); + } StringCchCat(nid.szTip,COUNTOF(nid.szTip),tchTitle); Shell_NotifyIcon(NIM_MODIFY,&nid); @@ -11167,24 +11228,6 @@ void CALLBACK PasteBoardTimer(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTi // //============================================================================= -static WIN32_FIND_DATA s_fdCurFile = { 0 }; - -static inline bool HasCurrentFileChanged() { - if (StrIsEmpty(Paths.CurrentFile)) { - return false; - } - WIN32_FIND_DATA fdUpdated = { 0 }; - if (!GetFileAttributesEx(Paths.CurrentFile, GetFileExInfoStandard, &fdUpdated)) { - return true; // The current file has been removed - } - bool const changed = (s_fdCurFile.nFileSizeLow != fdUpdated.nFileSizeLow) || (s_fdCurFile.nFileSizeHigh != fdUpdated.nFileSizeHigh) - //~|| (CompareFileTime(&s_fdCurFile.ftLastWriteTime, &fdUpdated.ftLastWriteTime) != 0) - || (s_fdCurFile.ftLastWriteTime.dwLowDateTime != fdUpdated.ftLastWriteTime.dwLowDateTime) - || (s_fdCurFile.ftLastWriteTime.dwHighDateTime != fdUpdated.ftLastWriteTime.dwHighDateTime); - return changed; -} -// ---------------------------------------------------------------------------- - static DWORD s_dwFileChangeNotifyTime = 0UL; static inline void NotifyIfFileHasChanged(const bool forcedNotify) { @@ -11344,9 +11387,7 @@ void InstallFileWatching(const bool bInstall) { if (!IS_VALID_HANDLE(_hObserverThread)) { // Save data of current file - if (!GetFileAttributesEx(Paths.CurrentFile, GetFileExInfoStandard, &s_fdCurFile)) { - ZeroMemory(&s_fdCurFile, sizeof(WIN32_FIND_DATA)); - } + ResetFileObservationData(false); WCHAR tchDirectory[MAX_PATH] = { L'\0' }; StringCchCopy(tchDirectory, COUNTOF(tchDirectory), Paths.CurrentFile); @@ -11396,7 +11437,6 @@ void InstallFileWatching(const bool bInstall) { if (bPrevReadOnlyAttrib && !s_bFileReadOnly) { SendWMCommand(Globals.hwndMain, IDM_FILE_READONLY); // try to reset } - } } UpdateTitleBar(Globals.hwndMain);