notepad-plus-plus/PowerEditor/src/NppBigSwitch.cpp
xomx 6000f3bb21 Fix session.xml emptying by forced Windows update restart
This fixes both the long standing problem with the emptying of the session.xml file by forced Windows Update restart/shutdown and some potential Notepad++ crashes caused by possible main Notepad++ window blocking at exit.

Two main changes to the original design:
- WM_QUERYENDSESSION is not used anymore for the tidy-up ops and it always quickly returns TRUE/FALSE to the system as it should.
- there is now a safe-guard flag for the session.xml saving at N++ exit, which prevents otherwise possible incorrect overwriting in case of multiple "endsession" messages.

Fix #9850, fix #12389, close #12388
2022-10-30 14:06:33 +01:00

3286 lines
90 KiB
C++
Raw Blame History

// This file is part of Notepad++ project
// Copyright (C)2021 Don HO <don.h@free.fr>
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// at your option any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <algorithm>
#include <shlwapi.h>
#include "Notepad_plus_Window.h"
#include "TaskListDlg.h"
#include "ImageListSet.h"
#include "ShortcutMapper.h"
#include "ansiCharPanel.h"
#include "clipboardHistoryPanel.h"
#include "VerticalFileSwitcher.h"
#include "ProjectPanel.h"
#include "documentMap.h"
#include "functionListPanel.h"
#include "fileBrowser.h"
#include "NppDarkMode.h"
using namespace std;
#define WM_DPICHANGED 0x02E0
struct SortTaskListPred final
{
DocTabView *_views[2];
SortTaskListPred(DocTabView &p, DocTabView &s)
{
_views[MAIN_VIEW] = &p;
_views[SUB_VIEW] = &s;
}
bool operator()(const TaskLstFnStatus &l, const TaskLstFnStatus &r) const {
BufferID lID = _views[l._iView]->getBufferByIndex(l._docIndex);
BufferID rID = _views[r._iView]->getBufferByIndex(r._docIndex);
Buffer * bufL = MainFileManager.getBufferByID(lID);
Buffer * bufR = MainFileManager.getBufferByID(rID);
return bufL->getRecentTag() > bufR->getRecentTag();
}
};
LRESULT CALLBACK Notepad_plus_Window::Notepad_plus_Proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if (hwnd == NULL)
return FALSE;
switch(message)
{
case WM_NCCREATE:
{
// First message we get the ptr of instantiated object
// then stock it into GWLP_USERDATA index in order to retrieve afterward
Notepad_plus_Window *pM30ide = static_cast<Notepad_plus_Window *>((reinterpret_cast<LPCREATESTRUCT>(lParam))->lpCreateParams);
pM30ide->_hSelf = hwnd;
::SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pM30ide));
if (NppDarkMode::isExperimentalSupported())
{
NppDarkMode::enableDarkScrollBarForWindowAndChildren(hwnd);
}
return TRUE;
}
default:
{
return (reinterpret_cast<Notepad_plus_Window *>(::GetWindowLongPtr(hwnd, GWLP_USERDATA))->runProc(hwnd, message, wParam, lParam));
}
}
}
LRESULT Notepad_plus_Window::runProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
{
try
{
NppDarkMode::setDarkTitleBar(hwnd);
_notepad_plus_plus_core._pPublicInterface = this;
LRESULT lRet = _notepad_plus_plus_core.init(hwnd);
if (NppDarkMode::isEnabled() && NppDarkMode::isExperimentalSupported())
{
RECT rcClient;
GetWindowRect(hwnd, &rcClient);
// Inform application of the frame change.
SetWindowPos(hwnd,
NULL,
rcClient.left, rcClient.top,
rcClient.right - rcClient.left, rcClient.bottom - rcClient.top,
SWP_FRAMECHANGED);
}
return lRet;
}
catch (std::exception& ex)
{
::MessageBoxA(hwnd, ex.what(), "Exception On WM_CREATE", MB_OK);
exit(-1);
}
break;
}
default:
{
return _notepad_plus_plus_core.process(hwnd, message, wParam, lParam);
}
}
}
// Used by NPPM_GETFILENAMEATCURSOR
int CharacterIs(TCHAR c, const TCHAR *any)
{
int i;
for (i = 0; any[i] != 0; i++)
{
if (any[i] == c) return TRUE;
}
return FALSE;
}
LRESULT Notepad_plus::process(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
LRESULT result = FALSE;
NppParameters& nppParam = NppParameters::getInstance();
if (NppDarkMode::isDarkMenuEnabled() && NppDarkMode::isEnabled() && NppDarkMode::runUAHWndProc(hwnd, message, wParam, lParam, &result))
{
return result;
}
switch (message)
{
case WM_NCACTIVATE:
{
// Note: lParam is -1 to prevent endless loops of calls
::SendMessage(_dockingManager.getHSelf(), WM_NCACTIVATE, wParam, -1);
result = ::DefWindowProc(hwnd, message, wParam, lParam);
if (NppDarkMode::isDarkMenuEnabled() && NppDarkMode::isEnabled())
{
NppDarkMode::drawUAHMenuNCBottomLine(hwnd);
}
NppDarkMode::calculateTreeViewStyle();
return result;
}
case WM_NCPAINT:
{
result = ::DefWindowProc(hwnd, message, wParam, lParam);
if (NppDarkMode::isDarkMenuEnabled() && NppDarkMode::isEnabled())
{
NppDarkMode::drawUAHMenuNCBottomLine(hwnd);
}
return result;
}
case WM_ERASEBKGND:
{
if (NppDarkMode::isEnabled())
{
RECT rc = {};
GetClientRect(hwnd, &rc);
::FillRect(reinterpret_cast<HDC>(wParam), &rc, NppDarkMode::getDarkerBackgroundBrush());
return 0;
}
else
{
return ::DefWindowProc(hwnd, message, wParam, lParam);
}
}
case WM_SETTINGCHANGE:
{
NppDarkMode::handleSettingChange(hwnd, lParam);
return ::DefWindowProc(hwnd, message, wParam, lParam);
}
case NPPM_INTERNAL_REFRESHDARKMODE:
{
refreshDarkMode(static_cast<bool>(wParam));
// Notify plugins that Dark Mode changed
SCNotification scnN{};
scnN.nmhdr.code = NPPN_DARKMODECHANGED;
scnN.nmhdr.hwndFrom = hwnd;
scnN.nmhdr.idFrom = 0;
_pluginsManager.notify(&scnN);
return TRUE;
}
case WM_DRAWITEM:
{
DRAWITEMSTRUCT *dis = reinterpret_cast<DRAWITEMSTRUCT *>(lParam);
if (dis->CtlType == ODT_TAB)
return ::SendMessage(dis->hwndItem, WM_DRAWITEM, wParam, lParam);
break;
}
case WM_DOCK_USERDEFINE_DLG:
{
dockUserDlg();
return TRUE;
}
case WM_UNDOCK_USERDEFINE_DLG:
{
undockUserDlg();
return TRUE;
}
case WM_REMOVE_USERLANG:
{
TCHAR *userLangName = reinterpret_cast<TCHAR *>(lParam);
if (!userLangName || !userLangName[0])
return FALSE;
generic_string name{userLangName};
//loop through buffers and reset the language (L_USER, TEXT("")) if (L_USER, name)
for (size_t i = 0; i < MainFileManager.getNbBuffers(); ++i)
{
Buffer* buf = MainFileManager.getBufferByIndex(i);
if (buf->getLangType() == L_USER && name == buf->getUserDefineLangName())
buf->setLangType(L_USER, TEXT(""));
}
return TRUE;
}
case WM_RENAME_USERLANG:
{
if (!lParam || !((reinterpret_cast<TCHAR *>(lParam))[0]) || !wParam || !((reinterpret_cast<TCHAR *>(wParam))[0]))
return FALSE;
generic_string oldName{ reinterpret_cast<TCHAR *>(lParam) };
generic_string newName{ reinterpret_cast<TCHAR *>(wParam) };
//loop through buffers and reset the language (L_USER, newName) if (L_USER, oldName)
for (size_t i = 0; i < MainFileManager.getNbBuffers(); ++i)
{
Buffer* buf = MainFileManager.getBufferByIndex(i);
if (buf->getLangType() == L_USER && oldName == buf->getUserDefineLangName())
buf->setLangType(L_USER, newName.c_str());
}
return TRUE;
}
case WM_CLOSE_USERDEFINE_DLG:
{
checkMenuItem(IDM_LANG_USER_DLG, false);
_toolBar.setCheck(IDM_LANG_USER_DLG, false);
return TRUE;
}
case WM_REPLACEALL_INOPENEDDOC:
{
replaceInOpenedFiles();
return TRUE;
}
case WM_FINDALL_INOPENEDDOC:
{
findInOpenedFiles();
return TRUE;
}
case WM_FINDALL_INCURRENTDOC:
{
const bool isEntireDoc = wParam == 0;
return findInCurrentFile(isEntireDoc);
}
case WM_FINDINFILES:
{
return findInFiles();
}
case WM_FINDINPROJECTS:
{
return findInProjects();
}
case WM_FINDALL_INCURRENTFINDER:
{
FindersInfo *findInFolderInfo = reinterpret_cast<FindersInfo *>(wParam);
Finder * newFinder = _findReplaceDlg.createFinder();
findInFolderInfo->_pDestFinder = newFinder;
bool isOK = findInFinderFiles(findInFolderInfo);
return isOK;
}
case WM_REPLACEINFILES:
{
replaceInFiles();
return TRUE;
}
case WM_REPLACEINPROJECTS:
{
replaceInProjects();
return TRUE;
}
case NPPM_LAUNCHFINDINFILESDLG:
{
// Find in files function code should be here due to the number of parameters (2) cannot be passed via WM_COMMAND
const int strSize = FINDREPLACE_MAXLENGTH;
TCHAR str[strSize];
bool isFirstTime = !_findReplaceDlg.isCreated();
_findReplaceDlg.doDialog(FIND_DLG, _nativeLangSpeaker.isRTL());
const NppGUI & nppGui = nppParam.getNppGUI();
if (nppGui._fillFindFieldWithSelected)
{
_pEditView->getGenericSelectedText(str, strSize, nppGui._fillFindFieldSelectCaret);
_findReplaceDlg.setSearchText(str);
}
if (isFirstTime)
_nativeLangSpeaker.changeFindReplaceDlgLang(_findReplaceDlg);
_findReplaceDlg.launchFindInFilesDlg();
setFindReplaceFolderFilter(reinterpret_cast<const TCHAR*>(wParam), reinterpret_cast<const TCHAR*>(lParam));
return TRUE;
}
case NPPM_INTERNAL_FINDINPROJECTS:
{
const int strSize = FINDREPLACE_MAXLENGTH;
TCHAR str[strSize];
bool isFirstTime = not _findReplaceDlg.isCreated();
_findReplaceDlg.doDialog(FIND_DLG, _nativeLangSpeaker.isRTL());
_pEditView->getGenericSelectedText(str, strSize);
_findReplaceDlg.setSearchText(str);
if (isFirstTime)
_nativeLangSpeaker.changeDlgLang(_findReplaceDlg.getHSelf(), "Find");
_findReplaceDlg.launchFindInProjectsDlg();
_findReplaceDlg.setProjectCheckmarks(NULL, (int) wParam);
return TRUE;
}
case NPPM_INTERNAL_FINDINFINDERDLG:
{
const int strSize = FINDREPLACE_MAXLENGTH;
TCHAR str[strSize];
Finder *launcher = reinterpret_cast<Finder *>(wParam);
bool isFirstTime = !_findInFinderDlg.isCreated();
_findInFinderDlg.doDialog(launcher, _nativeLangSpeaker.isRTL());
_pEditView->getGenericSelectedText(str, strSize);
_findReplaceDlg.setSearchText(str);
setFindReplaceFolderFilter(NULL, NULL);
if (isFirstTime)
_nativeLangSpeaker.changeFindReplaceDlgLang(_findReplaceDlg);
return TRUE;
}
case NPPM_DOOPEN:
case WM_DOOPEN:
{
BufferID id = doOpen(reinterpret_cast<const TCHAR *>(lParam));
if (id != BUFFER_INVALID)
return switchToFile(id);
break;
}
case NPPM_INTERNAL_SETFILENAME:
{
if (!lParam && !wParam)
return FALSE;
BufferID id = (BufferID)wParam;
Buffer * b = MainFileManager.getBufferByID(id);
if (b && b->getStatus() == DOC_UNNAMED)
{
b->setFileName(reinterpret_cast<const TCHAR*>(lParam));
return TRUE;
}
return FALSE;
}
case NPPM_GETBUFFERLANGTYPE:
{
if (!wParam)
return -1;
BufferID id = (BufferID)wParam;
Buffer * b = MainFileManager.getBufferByID(id);
return b->getLangType();
}
case NPPM_SETBUFFERLANGTYPE:
{
if (!wParam)
return FALSE;
if (lParam < L_TEXT || lParam >= L_EXTERNAL || lParam == L_USER)
return FALSE;
BufferID id = (BufferID)wParam;
Buffer * b = MainFileManager.getBufferByID(id);
b->setLangType((LangType)lParam);
return TRUE;
}
case NPPM_GETBUFFERENCODING:
{
if (!wParam)
return -1;
BufferID id = (BufferID)wParam;
Buffer * b = MainFileManager.getBufferByID(id);
return b->getUnicodeMode();
}
case NPPM_SETBUFFERENCODING:
{
if (!wParam)
return FALSE;
if (lParam < uni8Bit || lParam >= uniEnd)
return FALSE;
BufferID id = (BufferID)wParam;
Buffer * b = MainFileManager.getBufferByID(id);
if (b->getStatus() != DOC_UNNAMED || b->isDirty()) //do not allow to change the encoding if the file has any content
return FALSE;
b->setUnicodeMode((UniMode)lParam);
return TRUE;
}
case NPPM_GETBUFFERFORMAT:
{
if (!wParam)
return -1;
BufferID id = (BufferID)wParam;
Buffer * b = MainFileManager.getBufferByID(id);
return static_cast<LRESULT>(b->getEolFormat());
}
case NPPM_SETBUFFERFORMAT:
{
if (!wParam)
return FALSE;
EolType newFormat = convertIntToFormatType(static_cast<int>(lParam), EolType::unknown);
if (EolType::unknown == newFormat)
{
assert(false and "invalid buffer format message");
return FALSE;
}
BufferID id = (BufferID)wParam;
Buffer * b = MainFileManager.getBufferByID(id);
b->setEolFormat(newFormat);
return TRUE;
}
case NPPM_GETBUFFERIDFROMPOS:
{
DocTabView* pView = nullptr;
if (lParam == MAIN_VIEW)
pView = &_mainDocTab;
else if (lParam == SUB_VIEW)
pView = &_subDocTab;
else
return reinterpret_cast<LRESULT>(BUFFER_INVALID);
if ((size_t)wParam < pView->nbItem())
return reinterpret_cast<LRESULT>(pView->getBufferByIndex(wParam));
return reinterpret_cast<LRESULT>(BUFFER_INVALID);
}
case NPPM_GETCURRENTBUFFERID:
{
return reinterpret_cast<LRESULT>(_pEditView->getCurrentBufferID());
}
case NPPM_RELOADBUFFERID:
{
if (!wParam)
return FALSE;
return doReload(reinterpret_cast<BufferID>(wParam), lParam != 0);
}
case NPPM_RELOADFILE:
{
TCHAR longNameFullpath[MAX_PATH];
const TCHAR* pFilePath = reinterpret_cast<const TCHAR*>(lParam);
wcscpy_s(longNameFullpath, MAX_PATH, pFilePath);
if (_tcschr(longNameFullpath, '~'))
{
::GetLongPathName(longNameFullpath, longNameFullpath, MAX_PATH);
}
BufferID id = MainFileManager.getBufferFromName(longNameFullpath);
if (id != BUFFER_INVALID)
doReload(id, wParam != 0);
break;
}
case NPPM_SWITCHTOFILE :
{
BufferID id = MainFileManager.getBufferFromName(reinterpret_cast<const TCHAR *>(lParam));
if (id != BUFFER_INVALID)
return switchToFile(id);
return false;
}
case NPPM_SAVECURRENTFILE:
{
return fileSave();
}
case NPPM_SAVECURRENTFILEAS:
{
BufferID currentBufferID = _pEditView->getCurrentBufferID();
bool asCopy = wParam == TRUE;
const TCHAR *filename = reinterpret_cast<const TCHAR *>(lParam);
if (!filename) return FALSE;
return doSave(currentBufferID, filename, asCopy);
}
case NPPM_SAVEALLFILES:
{
return fileSaveAll();
}
case NPPM_SAVEFILE:
{
return fileSaveSpecific(reinterpret_cast<const TCHAR *>(lParam));
}
case NPPM_GETCURRENTNATIVELANGENCODING:
{
return _nativeLangSpeaker.getLangEncoding();
}
case NPPM_INTERNAL_DOCORDERCHANGED :
{
if (_pDocumentListPanel)
{
_pDocumentListPanel->updateTabOrder();
}
BufferID id = _pEditView->getCurrentBufferID();
// Notify plugins that current file is about to be closed
SCNotification scnN{};
scnN.nmhdr.code = NPPN_DOCORDERCHANGED;
scnN.nmhdr.hwndFrom = reinterpret_cast<void *>(lParam);
scnN.nmhdr.idFrom = reinterpret_cast<uptr_t>(id);
_pluginsManager.notify(&scnN);
return TRUE;
}
case NPPM_INTERNAL_EXPORTFUNCLISTANDQUIT:
{
checkMenuItem(IDM_VIEW_FUNC_LIST, true);
_toolBar.setCheck(IDM_VIEW_FUNC_LIST, true);
launchFunctionList();
_pFuncList->setClosed(false);
_pFuncList->serialize();
::PostMessage(_pPublicInterface->getHSelf(), WM_COMMAND, IDM_FILE_EXIT, 0);
}
break;
case NPPM_INTERNAL_PRNTANDQUIT:
{
::PostMessage(_pPublicInterface->getHSelf(), WM_COMMAND, IDM_FILE_PRINTNOW, 0);
::PostMessage(_pPublicInterface->getHSelf(), WM_COMMAND, IDM_FILE_EXIT, 0);
}
break;
case NPPM_DISABLEAUTOUPDATE:
{
NppGUI & nppGUI = nppParam.getNppGUI();
nppGUI._autoUpdateOpt._doAutoUpdate = false;
return TRUE;
}
case WM_SIZE:
{
RECT rc;
_pPublicInterface->getClientRect(rc);
if (lParam == 0)
lParam = MAKELPARAM(rc.right - rc.left, rc.bottom - rc.top);
::MoveWindow(_rebarTop.getHSelf(), 0, 0, rc.right, _rebarTop.getHeight(), TRUE);
_statusBar.adjustParts(rc.right);
::SendMessage(_statusBar.getHSelf(), WM_SIZE, wParam, lParam);
int rebarBottomHeight = _rebarBottom.getHeight();
int statusBarHeight = _statusBar.getHeight();
::MoveWindow(_rebarBottom.getHSelf(), 0, rc.bottom - rebarBottomHeight - statusBarHeight, rc.right, rebarBottomHeight, TRUE);
getMainClientRect(rc);
_dockingManager.reSizeTo(rc);
if (_pDocMap)
{
_pDocMap->doMove();
_pDocMap->reloadMap();
}
result = TRUE;
break;
}
case WM_MOVE:
{
result = TRUE;
break;
}
case WM_MOVING:
{
if (_pDocMap)
{
_pDocMap->doMove();
}
result = FALSE;
break;
}
case WM_SIZING:
{
result = FALSE;
break;
}
case WM_COPYDATA:
{
COPYDATASTRUCT *pCopyData = reinterpret_cast<COPYDATASTRUCT *>(lParam);
switch (pCopyData->dwData)
{
case COPYDATA_FULL_CMDLINE:
{
nppParam.setCmdLineString(static_cast<wchar_t*>(pCopyData->lpData));
break;
}
case COPYDATA_PARAMS:
{
const CmdLineParamsDTO *cmdLineParam = static_cast<const CmdLineParamsDTO *>(pCopyData->lpData); // CmdLineParams object from another instance
const DWORD cmdLineParamsSize = pCopyData->cbData; // CmdLineParams size from another instance
if (sizeof(CmdLineParamsDTO) == cmdLineParamsSize) // make sure the structure is the same
{
nppParam.setCmdlineParam(*cmdLineParam);
generic_string pluginMessage { nppParam.getCmdLineParams()._pluginMessage };
if (!pluginMessage.empty())
{
SCNotification scnN{};
scnN.nmhdr.code = NPPN_CMDLINEPLUGINMSG;
scnN.nmhdr.hwndFrom = hwnd;
scnN.nmhdr.idFrom = reinterpret_cast<uptr_t>(pluginMessage.c_str());
_pluginsManager.notify(&scnN);
}
}
else
{
#ifdef DEBUG
printStr(TEXT("sizeof(CmdLineParams) != cmdLineParamsSize\rCmdLineParams is formed by an instance of another version,\rwhereas your CmdLineParams has been modified in this instance."));
#endif
}
NppGUI nppGui = (NppGUI)nppParam.getNppGUI();
nppGui._isCmdlineNosessionActivated = cmdLineParam->_isNoSession;
break;
}
case COPYDATA_FILENAMESA:
{
char *fileNamesA = static_cast<char *>(pCopyData->lpData);
const CmdLineParamsDTO & cmdLineParams = nppParam.getCmdLineParams();
WcharMbcsConvertor& wmc = WcharMbcsConvertor::getInstance();
const wchar_t *fileNamesW = wmc.char2wchar(fileNamesA, CP_ACP);
loadCommandlineParams(fileNamesW, &cmdLineParams);
break;
}
case COPYDATA_FILENAMESW:
{
wchar_t *fileNamesW = static_cast<wchar_t *>(pCopyData->lpData);
const CmdLineParamsDTO & cmdLineParams = nppParam.getCmdLineParams();
loadCommandlineParams(fileNamesW, &cmdLineParams);
break;
}
}
return TRUE;
}
case WM_COMMAND:
{
if (HIWORD(wParam) == SCEN_SETFOCUS)
{
HWND hMain = _mainEditView.getHSelf(), hSec = _subEditView.getHSelf();
HWND hFocus = reinterpret_cast<HWND>(lParam);
if (hMain == hFocus)
switchEditViewTo(MAIN_VIEW);
else if (hSec == hFocus)
switchEditViewTo(SUB_VIEW);
else
{
//Other Scintilla, ignore
}
return TRUE;
}
else
{
command(LOWORD(wParam));
}
return TRUE;
}
case NPPM_INTERNAL_SAVECURRENTSESSION:
{
const NppGUI& nppGui = nppParam.getNppGUI();
if (nppGui._rememberLastSession && !nppGui._isCmdlineNosessionActivated)
{
Session currentSession;
getCurrentOpenedFiles(currentSession, true);
nppParam.writeSession(currentSession);
}
return TRUE;
}
case NPPM_INTERNAL_SAVEBACKUP:
{
if (NppParameters::getInstance().getNppGUI().isSnapshotMode())
{
MainFileManager.backupCurrentBuffer();
}
return TRUE;
}
case NPPM_INTERNAL_CHANGETABBAEICONS:
{
_mainDocTab.changeIcons(static_cast<unsigned char>(lParam));
_subDocTab.changeIcons(static_cast<unsigned char>(lParam));
//restart document list with the same icons as the DocTabs
if (_pDocumentListPanel)
{
if (!_pDocumentListPanel->isClosed()) // if doclist is open
{
//close the doclist
_pDocumentListPanel->display(false);
//clean doclist
_pDocumentListPanel->destroy();
_pDocumentListPanel = nullptr;
//relaunch with new icons
launchDocumentListPanel();
}
else //if doclist is closed
{
//clean doclist
_pDocumentListPanel->destroy();
_pDocumentListPanel = nullptr;
//relaunch doclist with new icons and close it
launchDocumentListPanel();
if (_pDocumentListPanel)
{
_pDocumentListPanel->display(false);
_pDocumentListPanel->setClosed(true);
checkMenuItem(IDM_VIEW_DOCLIST, false);
_toolBar.setCheck(IDM_VIEW_DOCLIST, false);
}
}
}
return TRUE;
}
case NPPM_INTERNAL_RELOADNATIVELANG:
{
reloadLang();
return TRUE;
}
case NPPM_INTERNAL_RELOADSTYLERS:
{
loadStyles();
return TRUE;
}
case NPPM_INTERNAL_PLUGINSHORTCUTMOTIFIED:
{
SCNotification scnN{};
scnN.nmhdr.code = NPPN_SHORTCUTREMAPPED;
scnN.nmhdr.hwndFrom = reinterpret_cast<void *>(lParam); // ShortcutKey structure
scnN.nmhdr.idFrom = (uptr_t)wParam; // cmdID
_pluginsManager.notify(&scnN);
return TRUE;
}
case NPPM_GETSHORTCUTBYCMDID:
{
int cmdID = static_cast<int32_t>(wParam); // cmdID
ShortcutKey *sk = reinterpret_cast<ShortcutKey *>(lParam); // ShortcutKey structure
return _pluginsManager.getShortcutByCmdID(cmdID, sk);
}
case NPPM_MENUCOMMAND:
{
command(static_cast<int32_t>(lParam));
return TRUE;
}
case NPPM_GETFULLCURRENTPATH:
case NPPM_GETCURRENTDIRECTORY:
case NPPM_GETFILENAME:
case NPPM_GETNAMEPART:
case NPPM_GETEXTPART:
{
TCHAR str[MAX_PATH] = { '\0' };
// par defaut : NPPM_GETCURRENTDIRECTORY
wcscpy_s(str, _pEditView->getCurrentBuffer()->getFullPathName());
TCHAR* fileStr = str;
if (message == NPPM_GETCURRENTDIRECTORY)
PathRemoveFileSpec(str);
else if (message == NPPM_GETFILENAME)
fileStr = PathFindFileName(str);
else if (message == NPPM_GETNAMEPART)
{
fileStr = PathFindFileName(str);
PathRemoveExtension(fileStr);
}
else if (message == NPPM_GETEXTPART)
fileStr = PathFindExtension(str);
// For the compability reason, if wParam is 0, then we assume the size of generic_string buffer (lParam) is large enough.
// otherwise we check if the generic_string buffer size is enough for the generic_string to copy.
if (wParam != 0)
{
if (lstrlen(fileStr) >= int(wParam))
{
return FALSE;
}
}
lstrcpy(reinterpret_cast<TCHAR *>(lParam), fileStr);
return TRUE;
}
case NPPM_GETCURRENTWORD:
case NPPM_GETCURRENTLINESTR:
{
const int strSize = CURRENTWORD_MAXLENGTH;
TCHAR str[strSize] = { '\0' };
TCHAR *pTchar = reinterpret_cast<TCHAR *>(lParam);
if (message == NPPM_GETCURRENTWORD)
_pEditView->getGenericSelectedText(str, strSize);
else if (message == NPPM_GETCURRENTLINESTR)
_pEditView->getLine(_pEditView->getCurrentLineNumber(), str, strSize);
// For the compability reason, if wParam is 0, then we assume the size of generic_string buffer (lParam) is large enough.
// otherwise we check if the generic_string buffer size is enough for the generic_string to copy.
if (wParam != 0)
{
if (lstrlen(str) >= int(wParam)) //buffer too small
{
return FALSE;
}
else //buffer large enough, perform safe copy
{
lstrcpyn(pTchar, str, static_cast<int32_t>(wParam));
return TRUE;
}
}
lstrcpy(pTchar, str);
return TRUE;
}
case NPPM_GETFILENAMEATCURSOR: // wParam = buffer length, lParam = (TCHAR*)buffer
{
const int strSize = CURRENTWORD_MAXLENGTH;
TCHAR str[strSize];
TCHAR strLine[strSize];
size_t lineNumber;
intptr_t col;
int hasSlash;
TCHAR *pTchar = reinterpret_cast<TCHAR *>(lParam);
_pEditView->getGenericSelectedText(str, strSize); // this is either the selected text, or the word under the cursor if there is no selection
hasSlash = FALSE;
for (int i = 0; str[i] != 0; i++)
if (CharacterIs(str[i], TEXT("\\/")))
hasSlash = TRUE;
if (hasSlash == FALSE)
{
// it's not a full file name so try to find the beginning and ending of it
intptr_t start;
intptr_t end;
const TCHAR *delimiters;
lineNumber = _pEditView->getCurrentLineNumber();
col = _pEditView->getCurrentColumnNumber();
_pEditView->getLine(lineNumber, strLine, strSize);
// find the start
start = col;
delimiters = TEXT(" \t[(\"<>");
while ((start > 0) && (CharacterIs(strLine[start], delimiters) == FALSE))
start--;
if (CharacterIs(strLine[start], delimiters)) start++;
// find the end
end = col;
delimiters = TEXT(" \t:()[]<>\"\r\n");
while ((strLine[end] != 0) && (CharacterIs(strLine[end], delimiters) == FALSE)) end++;
lstrcpyn(str, &strLine[start], static_cast<int>(end - start + 1));
}
if (lstrlen(str) >= int(wParam)) //buffer too small
{
return FALSE;
}
else //buffer large enough, perform safe copy
{
lstrcpyn(pTchar, str, static_cast<int32_t>(wParam));
return TRUE;
}
}
case NPPM_GETNPPFULLFILEPATH:
case NPPM_GETNPPDIRECTORY:
{
const int strSize = MAX_PATH;
TCHAR str[strSize];
::GetModuleFileName(NULL, str, strSize);
if (message == NPPM_GETNPPDIRECTORY)
PathRemoveFileSpec(str);
// For the compability reason, if wParam is 0, then we assume the size of generic_string buffer (lParam) is large enough.
// otherwise we check if the generic_string buffer size is enough for the generic_string to copy.
if (wParam != 0)
{
if (lstrlen(str) >= int(wParam))
{
return FALSE;
}
}
lstrcpy(reinterpret_cast<TCHAR *>(lParam), str);
return TRUE;
}
case NPPM_GETCURRENTLINE:
{
return _pEditView->getCurrentLineNumber();
}
case NPPM_GETCURRENTCOLUMN:
{
return _pEditView->getCurrentColumnNumber();
}
case NPPM_GETCURRENTSCINTILLA:
{
int *id = reinterpret_cast<int *>(lParam);
if (_pEditView == &_mainEditView)
*id = MAIN_VIEW;
else if (_pEditView == &_subEditView)
*id = SUB_VIEW;
else
*id = -1;
return TRUE;
}
case NPPM_GETCURRENTLANGTYPE:
{
*(reinterpret_cast<LangType *>(lParam)) = _pEditView->getCurrentBuffer()->getLangType();
return TRUE;
}
case NPPM_SETCURRENTLANGTYPE:
{
_pEditView->getCurrentBuffer()->setLangType(static_cast<LangType>(lParam));
return TRUE;
}
case NPPM_GETNBOPENFILES:
{
size_t nbDocPrimary = _mainDocTab.nbItem();
size_t nbDocSecond = _subDocTab.nbItem();
if (lParam == ALL_OPEN_FILES)
return nbDocPrimary + nbDocSecond;
else if (lParam == PRIMARY_VIEW)
return nbDocPrimary;
else if (lParam == SECOND_VIEW)
return nbDocSecond;
}
case NPPM_GETOPENFILENAMESPRIMARY:
case NPPM_GETOPENFILENAMESSECOND:
case NPPM_GETOPENFILENAMES:
{
if (!wParam)
return 0;
TCHAR** fileNames = reinterpret_cast<TCHAR**>(wParam);
size_t nbFileNames = static_cast<size_t>(lParam);
size_t j = 0;
if (message != NPPM_GETOPENFILENAMESSECOND)
{
for (size_t i = 0; i < _mainDocTab.nbItem() && j < nbFileNames; ++i)
{
BufferID id = _mainDocTab.getBufferByIndex(i);
Buffer * buf = MainFileManager.getBufferByID(id);
lstrcpy(fileNames[j++], buf->getFullPathName());
}
}
if (message != NPPM_GETOPENFILENAMESPRIMARY)
{
for (size_t i = 0; i < _subDocTab.nbItem() && j < nbFileNames; ++i)
{
BufferID id = _subDocTab.getBufferByIndex(i);
Buffer * buf = MainFileManager.getBufferByID(id);
lstrcpy(fileNames[j++], buf->getFullPathName());
}
}
return j;
}
case WM_GETTASKLISTINFO:
{
if (!wParam)
return 0;
TaskListInfo * tli = reinterpret_cast<TaskListInfo *>(wParam);
getTaskListInfo(tli);
if (lParam != 0)
{
for (size_t idx = 0; idx < tli->_tlfsLst.size(); ++idx)
{
if (tli->_tlfsLst[idx]._iView == currentView() &&
tli->_tlfsLst[idx]._docIndex == _pDocTab->getCurrentTabIndex())
{
tli->_currentIndex = static_cast<int>(idx);
break;
}
}
return TRUE;
}
if (NppParameters::getInstance().getNppGUI()._styleMRU)
{
tli->_currentIndex = 0;
std::sort(tli->_tlfsLst.begin(),tli->_tlfsLst.end(),SortTaskListPred(_mainDocTab,_subDocTab));
}
else
{
for (size_t idx = 0; idx < tli->_tlfsLst.size(); ++idx)
{
if (tli->_tlfsLst[idx]._iView == currentView() &&
tli->_tlfsLst[idx]._docIndex == _pDocTab->getCurrentTabIndex())
{
tli->_currentIndex = static_cast<int>(idx);
break;
}
}
}
return TRUE;
}
case WM_MOUSEWHEEL:
{
if (0 != (LOWORD(wParam) & MK_RBUTTON))
{
// redirect to the IDC_PREV_DOC or IDC_NEXT_DOC so that we have the unified process
nppParam._isTaskListRBUTTONUP_Active = true;
short zDelta = (short) HIWORD(wParam);
return ::SendMessage(hwnd, WM_COMMAND, zDelta>0?IDC_PREV_DOC:IDC_NEXT_DOC, 0);
}
return TRUE;
}
case WM_APPCOMMAND:
{
switch(GET_APPCOMMAND_LPARAM(lParam))
{
case APPCOMMAND_BROWSER_BACKWARD:
case APPCOMMAND_BROWSER_FORWARD:
{
size_t nbDoc = viewVisible(MAIN_VIEW) ? _mainDocTab.nbItem() : 0;
nbDoc += viewVisible(SUB_VIEW)?_subDocTab.nbItem():0;
if (nbDoc > 1)
activateNextDoc((GET_APPCOMMAND_LPARAM(lParam) == APPCOMMAND_BROWSER_FORWARD)?dirDown:dirUp);
_linkTriggered = true;
break;
}
}
return ::DefWindowProc(hwnd, message, wParam, lParam);
}
case NPPM_GETNBSESSIONFILES:
{
const TCHAR *sessionFileName = reinterpret_cast<const TCHAR *>(lParam);
if ((!sessionFileName) || (sessionFileName[0] == '\0'))
return 0;
Session session2Load;
if (nppParam.loadSession(session2Load, sessionFileName))
return session2Load.nbMainFiles() + session2Load.nbSubFiles();
return 0;
}
case NPPM_GETSESSIONFILES:
{
const TCHAR *sessionFileName = reinterpret_cast<const TCHAR *>(lParam);
TCHAR **sessionFileArray = reinterpret_cast<TCHAR **>(wParam);
if ((!sessionFileName) || (sessionFileName[0] == '\0'))
return FALSE;
Session session2Load;
if (nppParam.loadSession(session2Load, sessionFileName))
{
size_t i = 0;
for ( ; i < session2Load.nbMainFiles() ; )
{
const TCHAR *pFn = session2Load._mainViewFiles[i]._fileName.c_str();
lstrcpy(sessionFileArray[i++], pFn);
}
for (size_t j = 0, len = session2Load.nbSubFiles(); j < len ; ++j)
{
const TCHAR *pFn = session2Load._subViewFiles[j]._fileName.c_str();
lstrcpy(sessionFileArray[i++], pFn);
}
return TRUE;
}
return FALSE;
}
case NPPM_DECODESCI:
{
// convert to ASCII
ScintillaEditView *pSci;
if (wParam == MAIN_VIEW)
pSci = &_mainEditView;
else if (wParam == SUB_VIEW)
pSci = &_subEditView;
else
return -1;
// get text of current scintilla
auto length = pSci->execute(SCI_GETTEXTLENGTH, 0, 0) + 1;
char* buffer = new char[length];
pSci->execute(SCI_GETTEXT, length, reinterpret_cast<LPARAM>(buffer));
// convert here
UniMode unicodeMode = pSci->getCurrentBuffer()->getUnicodeMode();
Utf8_16_Write UnicodeConvertor;
UnicodeConvertor.setEncoding(unicodeMode);
length = UnicodeConvertor.convert(buffer, length-1);
// set text in target
pSci->execute(SCI_CLEARALL);
pSci->addText(length, UnicodeConvertor.getNewBuf());
pSci->execute(SCI_EMPTYUNDOBUFFER);
pSci->execute(SCI_SETCODEPAGE);
// set cursor position
pSci->execute(SCI_GOTOPOS);
// clean buffer
delete [] buffer;
return unicodeMode;
}
case NPPM_ENCODESCI:
{
// convert
ScintillaEditView *pSci;
if (wParam == MAIN_VIEW)
pSci = &_mainEditView;
else if (wParam == SUB_VIEW)
pSci = &_subEditView;
else
return -1;
// get text of current scintilla
auto length = pSci->execute(SCI_GETTEXTLENGTH, 0, 0) + 1;
char* buffer = new char[length];
pSci->execute(SCI_GETTEXT, length, reinterpret_cast<LPARAM>(buffer));
Utf8_16_Read UnicodeConvertor;
length = UnicodeConvertor.convert(buffer, length-1);
// set text in target
pSci->execute(SCI_CLEARALL);
pSci->addText(length, UnicodeConvertor.getNewBuf());
pSci->execute(SCI_EMPTYUNDOBUFFER);
// set cursor position
pSci->execute(SCI_GOTOPOS);
// clean buffer
delete [] buffer;
// set new encoding if BOM was changed by other programms
UniMode um = UnicodeConvertor.getEncoding();
(pSci->getCurrentBuffer())->setUnicodeMode(um);
(pSci->getCurrentBuffer())->setDirty(true);
return um;
}
case NPPM_ACTIVATEDOC:
case NPPM_TRIGGERTABBARCONTEXTMENU:
{
// similar to NPPM_ACTIVEDOC
int whichView = ((wParam != MAIN_VIEW) && (wParam != SUB_VIEW)) ? currentView() : static_cast<int32_t>(wParam);
int index = static_cast<int32_t>(lParam);
switchEditViewTo(whichView);
activateDoc(index);
if (message == NPPM_TRIGGERTABBARCONTEXTMENU)
{
// open here tab menu
NMHDR nmhdr{};
nmhdr.code = NM_RCLICK;
nmhdr.hwndFrom = (whichView == MAIN_VIEW)?_mainDocTab.getHSelf():_subDocTab.getHSelf();
nmhdr.idFrom = ::GetDlgCtrlID(nmhdr.hwndFrom);
::SendMessage(hwnd, WM_NOTIFY, nmhdr.idFrom, reinterpret_cast<LPARAM>(&nmhdr));
}
return TRUE;
}
// ADD_ZERO_PADDING == TRUE
//
// version | HIWORD | LOWORD
//------------------------------
// 8.9.6.4 | 8 | 964
// 9 | 9 | 0
// 6.9 | 6 | 900
// 6.6.6 | 6 | 660
// 13.6.6.6 | 13 | 666
//
//
// ADD_ZERO_PADDING == FALSE
//
// version | HIWORD | LOWORD
//------------------------------
// 8.9.6.4 | 8 | 964
// 9 | 9 | 0
// 6.9 | 6 | 9
// 6.6.6 | 6 | 66
// 13.6.6.6 | 13 | 666
case NPPM_GETNPPVERSION:
{
const TCHAR* verStr = VERSION_VALUE;
TCHAR mainVerStr[16];
TCHAR auxVerStr[16];
bool isDot = false;
int j = 0;
int k = 0;
for (int i = 0; verStr[i]; ++i)
{
if (verStr[i] == '.')
{
isDot = true;
}
else
{
if (!isDot)
mainVerStr[j++] = verStr[i];
else
auxVerStr[k++] = verStr[i];
}
}
mainVerStr[j] = '\0';
auxVerStr[k] = '\0';
// if auxVerStr length should less or equal to 3.
// if auxVer is less 3 digits, the padding (0) will be added.
bool addZeroPadding = wParam == TRUE;
if (addZeroPadding)
{
size_t nbDigit = lstrlen(auxVerStr);
if (nbDigit > 0 && nbDigit <= 3)
{
if (nbDigit == 3)
{
// OK, nothing to do.
}
else if (nbDigit == 2)
{
auxVerStr[2] = '0';
auxVerStr[3] = '\0';
}
else // if (nbDigit == 1)
{
auxVerStr[1] = '0';
auxVerStr[2] = '0';
auxVerStr[3] = '\0';
}
}
}
int mainVer = 0, auxVer = 0;
if (mainVerStr[0])
mainVer = generic_atoi(mainVerStr);
if (auxVerStr[0])
auxVer = generic_atoi(auxVerStr);
return MAKELONG(auxVer, mainVer);
}
case NPPM_GETCURRENTMACROSTATUS:
{
if (_recordingMacro)
return static_cast<LRESULT>(MacroStatus::RecordInProgress);
if (_playingBackMacro)
return static_cast<LRESULT>(MacroStatus::PlayingBack);
return (_macro.empty()) ? static_cast<LRESULT>(MacroStatus::Idle) : static_cast<LRESULT>(MacroStatus::RecordingStopped);
}
case NPPM_GETCURRENTCMDLINE:
{
generic_string cmdLineString = nppParam.getCmdLineString();
if (lParam != 0)
{
if (cmdLineString.length() >= static_cast<size_t>(wParam))
{
return 0;
}
lstrcpy(reinterpret_cast<TCHAR*>(lParam), cmdLineString.c_str());
}
return cmdLineString.length();
}
case NPPM_CREATELEXER:
{
WcharMbcsConvertor& wmc = WcharMbcsConvertor::getInstance();
const char* lexer_name = wmc.wchar2char(reinterpret_cast<TCHAR*>(lParam), CP_ACP);
return (LRESULT) CreateLexer(lexer_name);
}
case WM_FRSAVE_INT:
{
_macro.push_back(recordedMacroStep(static_cast<int32_t>(wParam), 0, lParam, NULL, recordedMacroStep::mtSavedSnR));
break;
}
case WM_FRSAVE_STR:
{
_macro.push_back(recordedMacroStep(static_cast<int32_t>(wParam), 0, 0, reinterpret_cast<const TCHAR *>(lParam), recordedMacroStep::mtSavedSnR));
break;
}
case WM_MACRODLGRUNMACRO:
{
if (!_recordingMacro) // if we're not currently recording, then playback the recorded keystrokes
{
int times = 1;
if (_runMacroDlg.getMode() == RM_RUN_MULTI)
times = _runMacroDlg.getTimes();
else if (_runMacroDlg.getMode() == RM_RUN_EOF)
times = -1;
else
break;
int counter = 0;
intptr_t lastLine = _pEditView->execute(SCI_GETLINECOUNT) - 1;
intptr_t currLine = _pEditView->getCurrentLineNumber();
int indexMacro = _runMacroDlg.getMacro2Exec();
intptr_t deltaLastLine = 0;
intptr_t deltaCurrLine = 0;
Macro m = _macro;
if (indexMacro != -1)
{
vector<MacroShortcut> & ms = nppParam.getMacroList();
m = ms[indexMacro].getMacro();
}
_pEditView->execute(SCI_BEGINUNDOACTION);
for (;;)
{
macroPlayback(m);
++counter;
if ( times >= 0 )
{
if ( counter >= times )
break;
}
else // run until eof
{
bool cursorMovedUp = deltaCurrLine < 0;
deltaLastLine = _pEditView->execute(SCI_GETLINECOUNT) - 1 - lastLine;
deltaCurrLine = _pEditView->getCurrentLineNumber() - currLine;
if (( deltaCurrLine == 0 ) // line no. not changed?
&& (deltaLastLine >= 0)) // and no lines removed?
break; // exit
// Update the line count, but only if the number of lines remaining is shrinking.
// Otherwise, the macro playback may never end.
if (deltaLastLine < deltaCurrLine)
lastLine += deltaLastLine;
// save current line
currLine += deltaCurrLine;
// eof?
if ((currLine > lastLine) || (currLine < 0)
|| ((deltaCurrLine == 0) && (currLine == 0) && ((deltaLastLine >= 0) || cursorMovedUp)))
{
break;
}
}
}
_pEditView->execute(SCI_ENDUNDOACTION);
}
break;
}
case NPPM_CREATESCINTILLAHANDLE:
{
return (LRESULT)_scintillaCtrls4Plugins.createSintilla((lParam ? reinterpret_cast<HWND>(lParam) : hwnd));
}
case NPPM_INTERNAL_GETSCINTEDTVIEW:
{
return (LRESULT)_scintillaCtrls4Plugins.getScintillaEditViewFrom(reinterpret_cast<HWND>(lParam));
}
case NPPM_INTERNAL_ENABLESNAPSHOT:
{
launchDocumentBackupTask();
return TRUE;
}
case NPPM_DESTROYSCINTILLAHANDLE:
{
//return _scintillaCtrls4Plugins.destroyScintilla(reinterpret_cast<HWND>(lParam));
// Destroying allocated Scintilla makes Notepad++ crash
// because created Scintilla view's pointer is added into _referees of Buffer object automatically.
// The deallocated scintilla view in _referees is used in Buffer::nextUntitledNewNumber().
// So we do nothing here and let Notepad++ destroy allocated Scintilla while it exits
// and we keep this message for the sake of compability withe the existing plugins.
return true;
}
case NPPM_GETNBUSERLANG:
{
if (lParam)
*(reinterpret_cast<int *>(lParam)) = IDM_LANG_USER;
return nppParam.getNbUserLang();
}
case NPPM_GETCURRENTDOCINDEX:
{
if (lParam == SUB_VIEW)
{
if (!viewVisible(SUB_VIEW))
return -1;
return _subDocTab.getCurrentTabIndex();
}
else //MAIN_VIEW
{
if (!viewVisible(MAIN_VIEW))
return -1;
return _mainDocTab.getCurrentTabIndex();
}
}
case NPPM_SETSTATUSBAR:
{
TCHAR *str2set = reinterpret_cast<TCHAR *>(lParam);
if (!str2set || !str2set[0])
return FALSE;
switch (wParam)
{
case STATUSBAR_DOC_TYPE:
case STATUSBAR_DOC_SIZE:
case STATUSBAR_CUR_POS:
case STATUSBAR_EOF_FORMAT:
case STATUSBAR_UNICODE_TYPE:
case STATUSBAR_TYPING_MODE:
_statusBar.setText(str2set, static_cast<int32_t>(wParam));
return TRUE;
default :
return FALSE;
}
}
case NPPM_GETMENUHANDLE:
{
if (wParam == NPPPLUGINMENU)
return (LRESULT)_pluginsManager.getMenuHandle();
else if (wParam == NPPMAINMENU)
return (LRESULT)_mainMenuHandle;
else
return static_cast<LRESULT>(NULL);
}
case NPPM_LOADSESSION:
{
fileLoadSession(reinterpret_cast<const TCHAR *>(lParam));
return TRUE;
}
case NPPM_SAVECURRENTSESSION:
{
return (LRESULT)fileSaveSession(0, NULL, reinterpret_cast<const TCHAR *>(lParam));
}
case NPPM_SAVESESSION:
{
sessionInfo *pSi = reinterpret_cast<sessionInfo *>(lParam);
return (LRESULT)fileSaveSession(pSi->nbFile, pSi->files, pSi->sessionFilePathName);
}
case NPPM_INTERNAL_CLEARSCINTILLAKEY:
{
_mainEditView.execute(SCI_CLEARCMDKEY, wParam);
_subEditView.execute(SCI_CLEARCMDKEY, wParam);
return TRUE;
}
case NPPM_INTERNAL_BINDSCINTILLAKEY:
{
_mainEditView.execute(SCI_ASSIGNCMDKEY, wParam, lParam);
_subEditView.execute(SCI_ASSIGNCMDKEY, wParam, lParam);
return TRUE;
}
case NPPM_INTERNAL_CMDLIST_MODIFIED:
{
::DrawMenuBar(hwnd);
return TRUE;
}
case NPPM_INTERNAL_MACROLIST_MODIFIED:
{
return TRUE;
}
case NPPM_INTERNAL_USERCMDLIST_MODIFIED:
{
return TRUE;
}
case NPPM_INTERNAL_FINDKEYCONFLICTS:
{
if (!wParam || !lParam) // Clean up current session
{
delete _pShortcutMapper;
_pShortcutMapper = nullptr;
return TRUE;
}
if (_pShortcutMapper == nullptr) // Begin new session
{
_pShortcutMapper = new ShortcutMapper;
if (_pShortcutMapper == nullptr)
break;
}
*reinterpret_cast<bool*>(lParam) = _pShortcutMapper->findKeyConflicts(nullptr, *reinterpret_cast<KeyCombo*>(wParam), (size_t)-1);
return TRUE;
}
case NPPM_INTERNAL_SETCARETWIDTH:
{
const NppGUI & nppGUI = nppParam.getNppGUI();
if (nppGUI._caretWidth < 4)
{
_mainEditView.execute(SCI_SETCARETSTYLE, CARETSTYLE_LINE);
_subEditView.execute(SCI_SETCARETSTYLE, CARETSTYLE_LINE);
_mainEditView.execute(SCI_SETCARETWIDTH, nppGUI._caretWidth);
_subEditView.execute(SCI_SETCARETWIDTH, nppGUI._caretWidth);
}
else if (nppGUI._caretWidth == 4)
{
_mainEditView.execute(SCI_SETCARETWIDTH, 1);
_subEditView.execute(SCI_SETCARETWIDTH, 1);
_mainEditView.execute(SCI_SETCARETSTYLE, CARETSTYLE_BLOCK);
_subEditView.execute(SCI_SETCARETSTYLE, CARETSTYLE_BLOCK);
}
else // nppGUI._caretWidth == 5
{
_mainEditView.execute(SCI_SETCARETWIDTH, 1);
_subEditView.execute(SCI_SETCARETWIDTH, 1);
_mainEditView.execute(SCI_SETCARETSTYLE, CARETSTYLE_BLOCK | CARETSTYLE_BLOCK_AFTER);
_subEditView.execute(SCI_SETCARETSTYLE, CARETSTYLE_BLOCK | CARETSTYLE_BLOCK_AFTER);
}
return TRUE;
}
case NPPM_SETSMOOTHFONT:
{
int param = (lParam == 0 ? SC_EFF_QUALITY_DEFAULT : SC_EFF_QUALITY_LCD_OPTIMIZED);
_mainEditView.execute(SCI_SETFONTQUALITY, param);
_subEditView.execute(SCI_SETFONTQUALITY, param);
return TRUE;
}
case NPPM_INTERNAL_CARETLINEFRAME:
{
_mainEditView.execute(SCI_SETCARETLINEFRAME, lParam);
_subEditView.execute(SCI_SETCARETLINEFRAME, lParam);
return TRUE;
}
case NPPM_SETEDITORBORDEREDGE:
{
bool withBorderEdge = (lParam == 1);
_mainEditView.setBorderEdge(withBorderEdge);
_subEditView.setBorderEdge(withBorderEdge);
return TRUE;
}
case NPPM_INTERNAL_VIRTUALSPACE:
{
const bool virtualSpace = (nppParam.getSVP())._virtualSpace;
int virtualSpaceOptions = SCVS_RECTANGULARSELECTION;
if(virtualSpace)
virtualSpaceOptions |= SCVS_USERACCESSIBLE | SCVS_NOWRAPLINESTART;
_mainEditView.execute(SCI_SETVIRTUALSPACEOPTIONS, virtualSpaceOptions);
_subEditView.execute(SCI_SETVIRTUALSPACEOPTIONS, virtualSpaceOptions);
return TRUE;
}
case NPPM_INTERNAL_SCROLLBEYONDLASTLINE:
{
const bool endAtLastLine = !(nppParam.getSVP())._scrollBeyondLastLine;
_mainEditView.execute(SCI_SETENDATLASTLINE, endAtLastLine);
_subEditView.execute(SCI_SETENDATLASTLINE, endAtLastLine);
return TRUE;
}
case NPPM_INTERNAL_SETWORDCHARS:
{
_mainEditView.setWordChars();
_subEditView.setWordChars();
return TRUE;
}
case NPPM_INTERNAL_SETMULTISELCTION:
{
const NppGUI & nppGUI = nppParam.getNppGUI();
_mainEditView.execute(SCI_SETMULTIPLESELECTION, nppGUI._enableMultiSelection);
_subEditView.execute(SCI_SETMULTIPLESELECTION, nppGUI._enableMultiSelection);
return TRUE;
}
case NPPM_INTERNAL_SETCARETBLINKRATE:
{
const NppGUI & nppGUI = nppParam.getNppGUI();
_mainEditView.execute(SCI_SETCARETPERIOD, nppGUI._caretBlinkRate);
_subEditView.execute(SCI_SETCARETPERIOD, nppGUI._caretBlinkRate);
return TRUE;
}
case NPPM_INTERNAL_ISTABBARREDUCED:
{
return _toReduceTabBar?TRUE:FALSE;
}
// ADD: success->hwnd; failure->NULL
// REMOVE: success->NULL; failure->hwnd
case NPPM_MODELESSDIALOG:
{
if (wParam == MODELESSDIALOGADD)
{
for (size_t i = 0, len = _hModelessDlgs.size() ; i < len ; ++i)
{
if (_hModelessDlgs[i] == reinterpret_cast<HWND>(lParam))
return static_cast<LRESULT>(NULL);
}
_hModelessDlgs.push_back(reinterpret_cast<HWND>(lParam));
return lParam;
}
else
{
if (wParam == MODELESSDIALOGREMOVE)
{
for (size_t i = 0, len = _hModelessDlgs.size(); i < len ; ++i)
{
if (_hModelessDlgs[i] == reinterpret_cast<HWND>(lParam))
{
vector<HWND>::iterator hDlg = _hModelessDlgs.begin() + i;
_hModelessDlgs.erase(hDlg);
return static_cast<LRESULT>(NULL);
}
}
return lParam;
}
}
return TRUE;
}
case WM_CONTEXTMENU:
{
if (nppParam._isTaskListRBUTTONUP_Active)
{
nppParam._isTaskListRBUTTONUP_Active = false;
}
else
{
if ((HWND(wParam) == _mainEditView.getHSelf()) || (HWND(wParam) == _subEditView.getHSelf()))
{
if ((HWND(wParam) == _mainEditView.getHSelf()))
switchEditViewTo(MAIN_VIEW);
else
switchEditViewTo(SUB_VIEW);
POINT p;
::GetCursorPos(&p);
ContextMenu scintillaContextmenu;
std::vector<MenuItemUnit>& tmp = nppParam.getContextMenuItems();
bool copyLink = (_pEditView->getSelectedTextCount() == 0) && _pEditView->getIndicatorRange(URL_INDIC);
scintillaContextmenu.create(hwnd, tmp, _mainMenuHandle, copyLink);
scintillaContextmenu.display(p);
return TRUE;
}
}
return ::DefWindowProc(hwnd, message, wParam, lParam);
}
case WM_NOTIFY:
{
NMHDR* nmhdr = reinterpret_cast<NMHDR*>(lParam);
if (nmhdr->code == NM_CUSTOMDRAW && (nmhdr->hwndFrom == _toolBar.getHSelf()))
{
NMTBCUSTOMDRAW* nmtbcd = reinterpret_cast<NMTBCUSTOMDRAW*>(lParam);
if (nmtbcd->nmcd.dwDrawStage == CDDS_PREERASE)
{
if (NppDarkMode::isEnabled())
{
FillRect(nmtbcd->nmcd.hdc, &nmtbcd->nmcd.rc, NppDarkMode::getDarkerBackgroundBrush());
nmtbcd->clrText = NppDarkMode::getTextColor();
SetTextColor(nmtbcd->nmcd.hdc, NppDarkMode::getTextColor());
return CDRF_SKIPDEFAULT;
}
else
{
return CDRF_DODEFAULT;
}
}
}
SCNotification *notification = reinterpret_cast<SCNotification *>(lParam);
if (notification->nmhdr.code == SCN_UPDATEUI)
{
checkClipboard(); //6
checkUndoState(); //4
}
if (wParam == LINKTRIGGERED)
notification->wParam = LINKTRIGGERED;
_pluginsManager.notify(notification);
return notify(notification);
}
case WM_ACTIVATEAPP:
{
if (wParam == TRUE) // if npp is about to be activated
{
::PostMessage(hwnd, NPPM_INTERNAL_CHECKDOCSTATUS, 0, 0);
}
return FALSE;
}
case NPPM_INTERNAL_CHECKDOCSTATUS:
{
// This is an workaround to deal with Microsoft issue in ReadDirectoryChanges notification
// If command prompt is used to write file continuously (e.g. ping -t 8.8.8.8 > ping.log)
// Then ReadDirectoryChanges does not detect the change.
// Fortunately, notification is sent if right click or double click happens on that file
// Let's leverage this as workaround to enhance npp file monitoring functionality.
// So calling "PathFileExists" is a workaround here.
Buffer* currBuf = getCurrentBuffer();
if (currBuf && currBuf->isMonitoringOn())
::PathFileExists(currBuf->getFullPathName());
const NppGUI & nppgui = nppParam.getNppGUI();
if (nppgui._fileAutoDetection != cdDisabled)
{
bool bCheckOnlyCurrentBuffer = (nppgui._fileAutoDetection & cdEnabledNew) ? true : false;
checkModifiedDocument(bCheckOnlyCurrentBuffer);
return TRUE;
}
return FALSE;
}
case NPPM_INTERNAL_RELOADSCROLLTOEND:
{
Buffer *buf = reinterpret_cast<Buffer *>(wParam);
buf->reload();
return TRUE;
}
case NPPM_INTERNAL_STOPMONITORING:
{
Buffer *buf = reinterpret_cast<Buffer *>(wParam);
monitoringStartOrStopAndUpdateUI(buf, false);
return TRUE;
}
case NPPM_GETPOSFROMBUFFERID:
{
int i;
if (lParam == SUB_VIEW)
{
if ((i = _subDocTab.getIndexByBuffer((BufferID)wParam)) != -1)
{
long view = SUB_VIEW;
view <<= 30;
return view|i;
}
if ((i = _mainDocTab.getIndexByBuffer((BufferID)wParam)) != -1)
{
long view = MAIN_VIEW;
view <<= 30;
return view|i;
}
}
else
{
if ((i = _mainDocTab.getIndexByBuffer((BufferID)wParam)) != -1)
{
long view = MAIN_VIEW;
view <<= 30;
return view|i;
}
if ((i = _subDocTab.getIndexByBuffer((BufferID)wParam)) != -1)
{
long view = SUB_VIEW;
view <<= 30;
return view|i;
}
}
return -1;
}
case NPPM_GETFULLPATHFROMBUFFERID:
{
return MainFileManager.getFileNameFromBuffer(reinterpret_cast<BufferID>(wParam), reinterpret_cast<TCHAR *>(lParam));
}
case NPPM_INTERNAL_ENABLECHECKDOCOPT:
{
NppGUI& nppgui = nppParam.getNppGUI();
if (wParam == CHECKDOCOPT_NONE)
nppgui._fileAutoDetection = cdDisabled;
else if (wParam == CHECKDOCOPT_UPDATESILENTLY)
nppgui._fileAutoDetection = (cdEnabledOld | cdAutoUpdate);
else if (wParam == CHECKDOCOPT_UPDATEGO2END)
nppgui._fileAutoDetection = (cdEnabledOld | cdGo2end);
else if (wParam == (CHECKDOCOPT_UPDATESILENTLY | CHECKDOCOPT_UPDATEGO2END))
nppgui._fileAutoDetection = (cdEnabledOld | cdGo2end | cdAutoUpdate);
return TRUE;
}
case WM_ACTIVATE:
{
if (wParam != WA_INACTIVE && _pEditView && _pNonEditView)
{
_pEditView->getFocus();
auto x = _pEditView->execute(SCI_GETXOFFSET);
_pEditView->execute(SCI_SETXOFFSET, x);
x = _pNonEditView->execute(SCI_GETXOFFSET);
_pNonEditView->execute(SCI_SETXOFFSET, x);
}
return TRUE;
}
case WM_SYNCPAINT:
{
RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN);
break;
}
case WM_DROPFILES:
{
dropFiles(reinterpret_cast<HDROP>(wParam));
return TRUE;
}
case WM_UPDATESCINTILLAS:
{
//reset styler for change in Stylers.xml
_mainEditView.defineDocType(_mainEditView.getCurrentBuffer()->getLangType());
_mainEditView.performGlobalStyles();
addHotSpot(& _mainEditView);
_subEditView.defineDocType(_subEditView.getCurrentBuffer()->getLangType());
_subEditView.performGlobalStyles();
addHotSpot(& _subEditView);
_findReplaceDlg.updateFinderScintilla();
drawTabbarColoursFromStylerArray();
drawDocumentMapColoursFromStylerArray();
// Update default fg/bg colors in Parameters for both internal/plugins docking dialog
const Style* pStyle = NppParameters::getInstance().getGlobalStylers().findByID(STYLE_DEFAULT);
if (pStyle)
{
NppParameters::getInstance().setCurrentDefaultFgColor(pStyle->_fgColor);
NppParameters::getInstance().setCurrentDefaultBgColor(pStyle->_bgColor);
drawAutocompleteColoursFromTheme(pStyle->_fgColor, pStyle->_bgColor);
}
AutoCompletion::drawAutocomplete(_pEditView);
AutoCompletion::drawAutocomplete(_pNonEditView);
NppDarkMode::calculateTreeViewStyle();
auto refreshOnlyTreeView = static_cast<LPARAM>(TRUE);
// Set default fg/bg colors on internal docking dialog
if (pStyle && _pFuncList)
{
_pFuncList->setBackgroundColor(pStyle->_bgColor);
_pFuncList->setForegroundColor(pStyle->_fgColor);
::SendMessage(_pFuncList->getHSelf(), NPPM_INTERNAL_REFRESHDARKMODE, 0, refreshOnlyTreeView);
}
if (pStyle && _pAnsiCharPanel)
{
_pAnsiCharPanel->setBackgroundColor(pStyle->_bgColor);
_pAnsiCharPanel->setForegroundColor(pStyle->_fgColor);
}
if (pStyle && _pDocumentListPanel)
{
_pDocumentListPanel->setBackgroundColor(pStyle->_bgColor);
_pDocumentListPanel->setForegroundColor(pStyle->_fgColor);
}
if (pStyle && _pClipboardHistoryPanel)
{
_pClipboardHistoryPanel->setBackgroundColor(pStyle->_bgColor);
_pClipboardHistoryPanel->setForegroundColor(pStyle->_fgColor);
_pClipboardHistoryPanel->redraw(true);
}
if (pStyle && _pProjectPanel_1)
{
_pProjectPanel_1->setBackgroundColor(pStyle->_bgColor);
_pProjectPanel_1->setForegroundColor(pStyle->_fgColor);
::SendMessage(_pProjectPanel_1->getHSelf(), NPPM_INTERNAL_REFRESHDARKMODE, 0, refreshOnlyTreeView);
}
if (pStyle && _pProjectPanel_2)
{
_pProjectPanel_2->setBackgroundColor(pStyle->_bgColor);
_pProjectPanel_2->setForegroundColor(pStyle->_fgColor);
::SendMessage(_pProjectPanel_2->getHSelf(), NPPM_INTERNAL_REFRESHDARKMODE, 0, refreshOnlyTreeView);
}
if (pStyle && _pProjectPanel_3)
{
_pProjectPanel_3->setBackgroundColor(pStyle->_bgColor);
_pProjectPanel_3->setForegroundColor(pStyle->_fgColor);
::SendMessage(_pProjectPanel_3->getHSelf(), NPPM_INTERNAL_REFRESHDARKMODE, 0, refreshOnlyTreeView);
}
if (pStyle && _pFileBrowser)
{
_pFileBrowser->setBackgroundColor(pStyle->_bgColor);
_pFileBrowser->setForegroundColor(pStyle->_fgColor);
::SendMessage(_pFileBrowser->getHSelf(), NPPM_INTERNAL_REFRESHDARKMODE, 0, refreshOnlyTreeView);
}
if (_pDocMap)
_pDocMap->setSyntaxHiliting();
// Notify plugins of update to styles xml
SCNotification scnN{};
scnN.nmhdr.code = NPPN_WORDSTYLESUPDATED;
scnN.nmhdr.hwndFrom = hwnd;
scnN.nmhdr.idFrom = (uptr_t) _pEditView->getCurrentBufferID();
_pluginsManager.notify(&scnN);
return TRUE;
}
case WM_UPDATEMAINMENUBITMAPS:
{
setupColorSampleBitmapsOnMainMenuItems();
return TRUE;
}
case WM_QUERYENDSESSION:
{
// app should return TRUE or FALSE immediately upon receiving this message,
// and defer any cleanup operations until it receives WM_ENDSESSION (with WPARAM TRUE)
// for a bigger tidy-up/save operations we can kick off a background thread here to prepare for shutdown
// and when we get the WM_END<4E>SESSION TRUE, we wait there until that background operation completes
// before telling the system, "ok, you can shut down now...", i.e. returning 0 there
// whatever we do from here - make sure that it is ok for the operation to occur even if the shutdown
// is then subsequently canceled
// here we could also display a prompt to ask the users whether they want to save their unsaved changes etc.,
// but in practice, this is usually not a good idea because if we do not respond to this message
// after a few seconds (e.g. user is away from PC...), the system will shut down without us
bool isFirstQueryEndSession = !nppParam.isEndSessionStarted();
bool isForcedShuttingDown = (lParam & ENDSESSION_CRITICAL);
nppParam.endSessionStart();
if (isForcedShuttingDown)
nppParam.makeEndSessionCritical();
if (nppParam.doNppLogNulContentCorruptionIssue())
{
generic_string issueFn = nppLogNulContentCorruptionIssue;
issueFn += TEXT(".log");
generic_string nppIssueLog = nppParam.getUserPath();
pathAppend(nppIssueLog, issueFn);
string wmqesType = std::to_string(lParam);
if (lParam == 0)
{
wmqesType += " - ordinary system shutdown/restart";
}
else
{
// the lParam here is a bit mask, it can be one or more of the following values
if (lParam & ENDSESSION_CLOSEAPP)
wmqesType += " - ENDSESSION_CLOSEAPP";
if (lParam & ENDSESSION_CRITICAL)
wmqesType += " - ENDSESSION_CRITICAL";
if (lParam & ENDSESSION_LOGOFF)
wmqesType += " - ENDSESSION_LOGOFF";
}
string msg = "WM_QUERYENDSESSION (lParam: " + wmqesType + ") =====================================";
writeLog(nppIssueLog.c_str(), msg.c_str());
}
if (::IsWindowEnabled(hwnd))
{
if (MainFileManager.getNbDirtyBuffers() > 0)
{
// we have unsaved filebuffer(s), give the user a chance to respond (non-critical shutdown only)
if (!isForcedShuttingDown && isFirstQueryEndSession)
{
// if N++ has been minimized or invisible, we need to show it 1st
if (::IsIconic(hwnd))
{
::ShowWindow(hwnd, SW_RESTORE);
}
else
{
if (!::IsWindowVisible(hwnd))
{
// systray etc...
::ShowWindow(hwnd, SW_SHOW);
::SendMessage(hwnd, WM_SIZE, 0, 0); // to make window fit (specially to show tool bar.)
}
}
::PostMessage(hwnd, WM_COMMAND, IDM_FILE_SAVEALL, 0); // posting will not block us here
return FALSE; // request abort of the shutdown
}
}
}
else
{
// we probably have a blocking modal-window like MessageBox (e.g. the "Reload" or "Keep non existing file")
if (!isForcedShuttingDown && isFirstQueryEndSession)
return FALSE; // request abort of the shutdown (for a non-critical one we can give the user a chance to solve whatever is needed)
// here is the right place to unblock the modal-dlg blocking the main N++ wnd, because then it will be too late
// to do so at the WM_ENDSESSION time (for that we need this thread message queue...)
// in most cases we will need to take care and programmatically close such dialogs in order to exit gracefully,
// otherwise the N++ most probably crashes itself without any tidy-up
string strLog = "Main N++ wnd is disabled by (an active modal-dlg?): ";
char szBuf[MAX_PATH + 128] = { 0 };
HWND hActiveWnd = ::GetActiveWindow();
if (hActiveWnd)
{
if (::GetWindowTextA(hActiveWnd, szBuf, _countof(szBuf)))
strLog += szBuf;
::SendMessage(hActiveWnd, WM_CLOSE, 0, 0);
}
else
{
// no active child window, so it is most probably the system dialog box class #32770 (used e.g. by the MessageBox WINAPI)
// - so our main hwnd here is not the PARENT but OWNER of that top-level window
hActiveWnd = ::GetLastActivePopup(hwnd);
if (hActiveWnd)
{
if (::GetWindowTextA(hActiveWnd, szBuf, _countof(szBuf)))
strLog += szBuf;
::GetClassNameA(hActiveWnd, szBuf, _countof(szBuf));
if (lstrcmpiA("#32770", szBuf) == 0)
strLog += " (MessageBox)";
// we cannot use here the usual sending of the WM_CLOSE as it will not always work (e.g. for a MB_YESNO MessageBox)
if (!::EndDialog(hActiveWnd, 0))
{
strLog += " -> EndDialog failed with ErrorCode: ";
strLog += std::to_string(::GetLastError());
// last attempt
::SendMessage(hActiveWnd, WM_SYSCOMMAND, SC_CLOSE, 0);
}
}
else
{
strLog += "???";
}
}
// re-test
if (::IsWindowEnabled(hwnd))
strLog += " -> Main N++ wnd has been successfully reenabled.";
if (nppParam.doNppLogNulContentCorruptionIssue())
{
generic_string issueFn = nppLogNulContentCorruptionIssue;
issueFn += TEXT(".log");
generic_string nppIssueLog = nppParam.getUserPath();
pathAppend(nppIssueLog, issueFn);
writeLog(nppIssueLog.c_str(), strLog.c_str());
}
}
// TODO: here is the last opportunity to call the following WINAPI in a possible future version of the N++
//
// flags RESTART_NO_PATCH and RESTART_NO_REBOOT are not set, so we should be restarted if terminated by an update or restart
//::RegisterApplicationRestart(restartCommandLine.c_str(), RESTART_NO_CRASH | RESTART_NO_HANG);
return TRUE; // nowadays, with the monstrous Win10+ Windows Update behind, is futile to try to interrupt the shutdown by returning FALSE here
// (if one really needs so, there is the ShutdownBlockReasonCreate WINAPI for the rescue ...)
}
case WM_ENDSESSION:
{
// this message informs our app whether the session is really ending
if (nppParam.doNppLogNulContentCorruptionIssue())
{
generic_string issueFn = nppLogNulContentCorruptionIssue;
issueFn += TEXT(".log");
generic_string nppIssueLog = nppParam.getUserPath();
pathAppend(nppIssueLog, issueFn);
string wmesType = std::to_string(lParam);
if (lParam == 0)
{
wmesType += " - ordinary system shutdown/restart";
}
else
{
// the lParam here is a bit mask, it can be one or more of the following values
if (lParam & ENDSESSION_CLOSEAPP)
wmesType += " - ENDSESSION_CLOSEAPP";
if (lParam & ENDSESSION_CRITICAL)
wmesType += " - ENDSESSION_CRITICAL";
if (lParam & ENDSESSION_LOGOFF)
wmesType += " - ENDSESSION_LOGOFF";
}
string msg = "WM_ENDSESSION (wParam: ";
if (wParam)
msg += "TRUE, lParam: ";
else
msg += "FALSE, lParam: ";
msg += wmesType + ")";
writeLog(nppIssueLog.c_str(), msg.c_str());
}
if (wParam == FALSE)
{
// the session is not being ended after all
// - it happens when either the N++ returns FALSE to non-critical WM_QUERYENDSESSION or any other app with higher shutdown level
// than N++ (app shuttdown order can be checked by the GetProcessShutdownParameters WINAPI)
// - we will not try to reset back our nppParam _isEndSessionStarted flag somehow, because of we should now that there was already
// a previous shutdown attempt, otherwise we could stubbornly repeat returning FALSE for the next WM_QUERYENDSESSION and
// the system will terminate us
return 0; // return here and do not continue to the WM_CLOSE part
}
else
{
// the session is being ended, it can end ANY TIME after all apps running have returned from processing this message,
// so DO NOT e.g. Send/Post any message from here onwards!!!
nppParam.endSessionStart(); // ensure
nppParam.makeEndSessionCritical(); // set our exit-flag to critical even if the bitmask has not the ENDSESSION_CRITICAL set
// do not return 0 here and continue to the N++ standard WM_CLOSE code-part (no verbose GUI there this time!!!)
}
} // case WM_ENDSESSION:
case WM_CLOSE:
{
if (nppParam.doNppLogNulContentCorruptionIssue() && nppParam.isEndSessionStarted() && (message == WM_CLOSE))
{
generic_string issueFn = nppLogNulContentCorruptionIssue;
issueFn += TEXT(".log");
generic_string nppIssueLog = nppParam.getUserPath();
pathAppend(nppIssueLog, issueFn);
writeLog(nppIssueLog.c_str(), "WM_CLOSE (isEndSessionStarted == true)");
}
if (_pPublicInterface->isPrelaunch())
{
SendMessage(hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0);
}
else
{
SCNotification scnN{};
scnN.nmhdr.hwndFrom = hwnd;
scnN.nmhdr.idFrom = 0;
scnN.nmhdr.code = NPPN_BEFORESHUTDOWN;
_pluginsManager.notify(&scnN);
if (_pTrayIco)
_pTrayIco->doTrayIcon(REMOVE);
const NppGUI & nppgui = nppParam.getNppGUI();
bool isSnapshotMode = nppgui.isSnapshotMode();
if (isSnapshotMode)
{
::LockWindowUpdate(hwnd);
MainFileManager.backupCurrentBuffer();
}
Session currentSession;
if (!((nppgui._multiInstSetting == monoInst) && !nppgui._rememberLastSession))
getCurrentOpenedFiles(currentSession, true);
if (nppgui._rememberLastSession)
{
//Lock the recent file list so it isnt populated with opened files
//Causing them to show on restart even though they are loaded by session
_lastRecentFileList.setLock(true); //only lock when the session is remembered
}
_isAttemptingCloseOnQuit = true;
bool allClosed = fileCloseAll(false, isSnapshotMode); //try closing files before doing anything else
_isAttemptingCloseOnQuit = false;
if (nppgui._rememberLastSession)
_lastRecentFileList.setLock(false); //only lock when the session is remembered
if (!saveProjectPanelsParams()) allClosed = false; //writeProjectPanelsSettings
saveFileBrowserParam();
saveColumnEditorParams();
if (!allClosed && !nppParam.isEndSessionCritical())
{
// cancelled by user
scnN.nmhdr.code = NPPN_CANCELSHUTDOWN;
_pluginsManager.notify(&scnN);
if (isSnapshotMode)
::LockWindowUpdate(NULL);
return 0; // abort quitting
}
if (_beforeSpecialView._isFullScreen) //closing, return to windowed mode
fullScreenToggle();
if (_beforeSpecialView._isPostIt) //closing, return to windowed mode
postItToggle();
if (_configStyleDlg.isCreated() && ::IsWindowVisible(_configStyleDlg.getHSelf()))
_configStyleDlg.restoreGlobalOverrideValues();
scnN.nmhdr.code = NPPN_SHUTDOWN;
_pluginsManager.notify(&scnN);
saveScintillasZoom();
saveGUIParams(); //writeGUIParams writeScintillaParams
saveFindHistory(); //writeFindHistory
_lastRecentFileList.saveLRFL(); //writeRecentFileHistorySettings, writeHistory
//
// saving config.xml
//
nppParam.saveConfig_xml();
//
// saving userDefineLang.xml
//
saveUserDefineLangs();
//
// saving shortcuts.xml
//
saveShortcuts();
if (!_isNppSessionSavedAtExit)
{
_isNppSessionSavedAtExit = true; // prevents emptying of the session.xml file on another WM_ENDSESSION or WM_CLOSE
//
// saving session.xml
//
if (nppgui._rememberLastSession && !nppgui._isCmdlineNosessionActivated)
saveSession(currentSession);
//
// saving session.xml into loaded session if a saved session is loaded and saveLoadedSessionOnExit option is enabled
//
generic_string loadedSessionFilePath = nppParam.getLoadedSessionFilePath();
if (!loadedSessionFilePath.empty() && PathFileExists(loadedSessionFilePath.c_str()))
nppParam.writeSession(currentSession, loadedSessionFilePath.c_str());
}
// write settings on cloud if enabled, if the settings files don't exist
if (nppgui._cloudPath != TEXT("") && nppParam.isCloudPathChanged())
{
bool isOK = nppParam.writeSettingsFilesOnCloudForThe1stTime(nppgui._cloudPath);
if (!isOK)
{
_nativeLangSpeaker.messageBox("SettingsOnCloudError",
hwnd,
TEXT("It seems the path of settings on cloud is set on a read only drive,\ror on a folder needed privilege right for writing access.\rYour settings on cloud will be canceled. Please reset a coherent value via Preference dialog."),
TEXT("Settings on Cloud"),
MB_OK | MB_APPLMODAL);
nppParam.removeCloudChoice();
}
}
if (isSnapshotMode)
::LockWindowUpdate(NULL);
//Sends WM_DESTROY, Notepad++ will end
::DestroyWindow(hwnd);
if (!nppParam.isEndSessionCritical())
{
generic_string updaterFullPath = nppParam.getWingupFullPath();
if (!updaterFullPath.empty())
{
Process updater(updaterFullPath.c_str(), nppParam.getWingupParams().c_str(), nppParam.getWingupDir().c_str());
updater.run(nppParam.shouldDoUAC());
}
}
}
return 0; // both WM_CLOSE and a possible WM_ENDSESSION should return 0
}
case WM_DESTROY:
{
if (nppParam.isEndSessionStarted() && nppParam.doNppLogNulContentCorruptionIssue())
{
generic_string issueFn = nppLogNulContentCorruptionIssue;
issueFn += TEXT(".log");
generic_string nppIssueLog = nppParam.getUserPath();
pathAppend(nppIssueLog, issueFn);
writeLog(nppIssueLog.c_str(), "WM_DESTROY (isEndSessionStarted == true)");
}
killAllChildren();
::PostQuitMessage(0);
_pPublicInterface->gNppHWND = NULL;
return TRUE;
}
case WM_SYSCOMMAND:
{
const NppGUI & nppgui = (nppParam.getNppGUI());
if ((nppgui._isMinimizedToTray || _pPublicInterface->isPrelaunch()) && (wParam == SC_MINIMIZE))
{
if (nullptr == _pTrayIco)
_pTrayIco = new trayIconControler(hwnd, IDI_M30ICON, NPPM_INTERNAL_MINIMIZED_TRAY, ::LoadIcon(_pPublicInterface->getHinst(), MAKEINTRESOURCE(IDI_M30ICON)), TEXT(""));
_pTrayIco->doTrayIcon(ADD);
_dockingManager.showFloatingContainers(false);
minimizeDialogs();
::ShowWindow(hwnd, SW_HIDE);
return TRUE;
}
if (wParam == SC_KEYMENU && lParam == VK_SPACE)
{
_sysMenuEntering = true;
}
else if (wParam == 0xF093) //it should be SC_MOUSEMENU. A bug?
{
_sysMenuEntering = true;
}
return ::DefWindowProc(hwnd, message, wParam, lParam);
}
case WM_LBUTTONDBLCLK:
{
::SendMessage(hwnd, WM_COMMAND, IDM_FILE_NEW, 0);
return TRUE;
}
case NPPM_INTERNAL_MINIMIZED_TRAY:
{
switch (lParam)
{
//case WM_LBUTTONDBLCLK:
case WM_LBUTTONUP :
{
_pEditView->getFocus();
::ShowWindow(hwnd, SW_SHOW);
_dockingManager.showFloatingContainers(true);
restoreMinimizeDialogs();
if (!_pPublicInterface->isPrelaunch())
_pTrayIco->doTrayIcon(REMOVE);
::SendMessage(hwnd, WM_SIZE, 0, 0);
return TRUE;
}
case WM_MBUTTONUP:
{
command(IDM_SYSTRAYPOPUP_NEW_AND_PASTE);
return TRUE;
}
case WM_RBUTTONUP:
{
POINT p;
GetCursorPos(&p);
HMENU hmenu; // menu template
HMENU hTrayIconMenu; // shortcut menu
hmenu = ::LoadMenu(_pPublicInterface->getHinst(), MAKEINTRESOURCE(IDR_SYSTRAYPOPUP_MENU));
hTrayIconMenu = ::GetSubMenu(hmenu, 0);
SetForegroundWindow(hwnd);
TrackPopupMenu(hTrayIconMenu, TPM_LEFTALIGN, p.x, p.y, 0, hwnd, NULL);
PostMessage(hwnd, WM_NULL, 0, 0);
DestroyMenu(hmenu);
return TRUE;
}
}
return TRUE;
}
case NPPM_DMMSHOW:
{
_dockingManager.showDockableDlg(reinterpret_cast<HWND>(lParam), SW_SHOW);
return TRUE;
}
case NPPM_DMMHIDE:
{
_dockingManager.showDockableDlg(reinterpret_cast<HWND>(lParam), SW_HIDE);
return TRUE;
}
case NPPM_DMMUPDATEDISPINFO:
{
if (::IsWindowVisible(reinterpret_cast<HWND>(lParam)))
_dockingManager.updateContainerInfo(reinterpret_cast<HWND>(lParam));
return TRUE;
}
case NPPM_DMMREGASDCKDLG:
{
tTbData *pData = reinterpret_cast<tTbData *>(lParam);
int iCont = -1;
bool isVisible = false;
getIntegralDockingData(*pData, iCont, isVisible);
_dockingManager.createDockableDlg(*pData, iCont, isVisible);
return TRUE;
}
case NPPM_DMMVIEWOTHERTAB:
{
_dockingManager.showDockableDlg(reinterpret_cast<TCHAR *>(lParam), SW_SHOW);
return TRUE;
}
case NPPM_DMMGETPLUGINHWNDBYNAME : //(const TCHAR *windowName, const TCHAR *moduleName)
{
if (!lParam)
return static_cast<LRESULT>(NULL);
TCHAR *moduleName = reinterpret_cast<TCHAR *>(lParam);
TCHAR *windowName = reinterpret_cast<TCHAR *>(wParam);
std::vector<DockingCont *> dockContainer = _dockingManager.getContainerInfo();
for (size_t i = 0, len = dockContainer.size(); i < len ; ++i)
{
std::vector<tTbData *> tbData = dockContainer[i]->getDataOfAllTb();
for (size_t j = 0, len2 = tbData.size() ; j < len2 ; ++j)
{
if (generic_stricmp(moduleName, tbData[j]->pszModuleName) == 0)
{
if (!windowName)
return (LRESULT)tbData[j]->hClient;
if (generic_stricmp(windowName, tbData[j]->pszName) == 0)
return (LRESULT)tbData[j]->hClient;
}
}
}
return static_cast<LRESULT>(NULL);
}
case NPPM_ADDTOOLBARICON_DEPRECATED:
{
_toolBar.registerDynBtn(static_cast<UINT>(wParam), reinterpret_cast<toolbarIcons*>(lParam), _pPublicInterface->getAbsentIcoHandle());
return TRUE;
}
case NPPM_ADDTOOLBARICON_FORDARKMODE:
{
_toolBar.registerDynBtnDM(static_cast<UINT>(wParam), reinterpret_cast<toolbarIconsWithDarkMode*>(lParam));
return TRUE;
}
case NPPM_SETMENUITEMCHECK:
{
::CheckMenuItem(_mainMenuHandle, static_cast<UINT>(wParam), MF_BYCOMMAND | (static_cast<BOOL>(lParam) ? MF_CHECKED : MF_UNCHECKED));
_toolBar.setCheck(static_cast<int>(wParam), lParam != 0);
return TRUE;
}
case NPPM_GETWINDOWSVERSION:
{
return (NppParameters::getInstance()).getWinVersion();
}
case NPPM_MAKECURRENTBUFFERDIRTY:
{
_pEditView->getCurrentBuffer()->setDirty(true);
return TRUE;
}
case NPPM_GETENABLETHEMETEXTUREFUNC:
{
return (LRESULT)nppParam.getEnableThemeDlgTexture();
}
case NPPM_GETPLUGINSCONFIGDIR:
{
generic_string userPluginConfDir = nppParam.getUserPluginConfDir();
if (lParam != 0)
{
if (userPluginConfDir.length() >= static_cast<size_t>(wParam))
{
return 0;
}
lstrcpy(reinterpret_cast<TCHAR *>(lParam), userPluginConfDir.c_str());
// For the retro-compatibility
return TRUE;
}
return userPluginConfDir.length();
}
case NPPM_GETPLUGINHOMEPATH:
{
generic_string pluginHomePath = nppParam.getPluginRootDir();
if (lParam != 0)
{
if (pluginHomePath.length() >= static_cast<size_t>(wParam))
{
return 0;
}
lstrcpy(reinterpret_cast<TCHAR *>(lParam), pluginHomePath.c_str());
}
return pluginHomePath.length();
}
case NPPM_GETSETTINGSONCLOUDPATH:
{
const NppGUI & nppGUI = nppParam.getNppGUI();
generic_string settingsOnCloudPath = nppGUI._cloudPath;
if (lParam != 0)
{
if (settingsOnCloudPath.length() >= static_cast<size_t>(wParam))
{
return 0;
}
lstrcpy(reinterpret_cast<TCHAR *>(lParam), settingsOnCloudPath.c_str());
}
return settingsOnCloudPath.length();
}
case NPPM_SETLINENUMBERWIDTHMODE:
{
if (lParam != LINENUMWIDTH_DYNAMIC && lParam != LINENUMWIDTH_CONSTANT)
return FALSE;
ScintillaViewParams &svp = const_cast<ScintillaViewParams &>(nppParam.getSVP());
svp._lineNumberMarginDynamicWidth = lParam == LINENUMWIDTH_DYNAMIC;
::SendMessage(hwnd, WM_COMMAND, IDM_VIEW_LINENUMBER, 0);
return TRUE;
}
case NPPM_GETLINENUMBERWIDTHMODE:
{
const ScintillaViewParams &svp = nppParam.getSVP();
return svp._lineNumberMarginDynamicWidth ? LINENUMWIDTH_DYNAMIC : LINENUMWIDTH_CONSTANT;
}
case NPPM_MSGTOPLUGIN :
{
return _pluginsManager.relayPluginMessages(message, wParam, lParam);
}
case NPPM_ALLOCATESUPPORTED:
{
return TRUE;
}
case NPPM_ALLOCATECMDID:
{
return _pluginsManager.allocateCmdID(static_cast<int32_t>(wParam), reinterpret_cast<int *>(lParam));
}
case NPPM_ALLOCATEMARKER:
{
return _pluginsManager.allocateMarker(static_cast<int32_t>(wParam), reinterpret_cast<int *>(lParam));
}
case NPPM_GETBOOKMARKID:
{
return MARK_BOOKMARK;
}
case NPPM_HIDETABBAR:
{
bool hide = (lParam != 0);
bool oldVal = DocTabView::getHideTabBarStatus();
if (hide == oldVal) return oldVal;
DocTabView::setHideTabBarStatus(hide);
::SendMessage(hwnd, WM_SIZE, 0, 0);
NppGUI & nppGUI = (NppParameters::getInstance()).getNppGUI();
if (hide)
nppGUI._tabStatus |= TAB_HIDE;
else
nppGUI._tabStatus &= ~TAB_HIDE;
return oldVal;
}
case NPPM_ISTABBARHIDDEN:
{
return _mainDocTab.getHideTabBarStatus();
}
case NPPM_HIDETOOLBAR:
{
bool show = (lParam != TRUE);
bool currentStatus = _rebarTop.getIDVisible(REBAR_BAR_TOOLBAR);
if (show != currentStatus)
_rebarTop.setIDVisible(REBAR_BAR_TOOLBAR, show);
return currentStatus;
}
case NPPM_ISTOOLBARHIDDEN :
{
return !_rebarTop.getIDVisible(REBAR_BAR_TOOLBAR);
}
case NPPM_HIDEMENU:
{
bool hide = (lParam == TRUE);
bool isHidden = ::GetMenu(hwnd) == NULL;
if (hide == isHidden)
return isHidden;
NppGUI & nppGUI = nppParam.getNppGUI();
nppGUI._menuBarShow = !hide;
if (nppGUI._menuBarShow)
::SetMenu(hwnd, _mainMenuHandle);
else
::SetMenu(hwnd, NULL);
return isHidden;
}
case NPPM_ISMENUHIDDEN:
{
return (::GetMenu(hwnd) == NULL);
}
case NPPM_HIDESTATUSBAR:
{
bool show = (lParam != TRUE);
NppGUI & nppGUI = nppParam.getNppGUI();
bool oldVal = nppGUI._statusBarShow;
if (show == oldVal)
return oldVal;
RECT rc;
_pPublicInterface->getClientRect(rc);
nppGUI._statusBarShow = show;
_statusBar.display(nppGUI._statusBarShow);
::SendMessage(hwnd, WM_SIZE, SIZE_RESTORED, MAKELONG(rc.bottom, rc.right));
return oldVal;
}
case NPPM_ISSTATUSBARHIDDEN:
{
const NppGUI & nppGUI = nppParam.getNppGUI();
return !nppGUI._statusBarShow;
}
case NPPM_GETCURRENTVIEW:
{
return _activeView;
}
case NPPM_INTERNAL_ISFOCUSEDTAB:
{
HWND hTabToTest = (currentView() == MAIN_VIEW)?_mainDocTab.getHSelf():_subDocTab.getHSelf();
return reinterpret_cast<HWND>(lParam) == hTabToTest;
}
case NPPM_INTERNAL_GETMENU:
{
return (LRESULT)_mainMenuHandle;
}
case NPPM_INTERNAL_CLEARINDICATOR:
{
_pEditView->clearIndicator(SCE_UNIVERSAL_FOUND_STYLE_SMART);
return TRUE;
}
case NPPM_INTERNAL_CLEARINDICATORTAGMATCH:
{
_pEditView->clearIndicator(SCE_UNIVERSAL_TAGMATCH);
_pEditView->clearIndicator(SCE_UNIVERSAL_TAGATTR);
return TRUE;
}
case NPPM_INTERNAL_CLEARINDICATORTAGATTR:
{
_pEditView->clearIndicator(SCE_UNIVERSAL_TAGATTR);
return TRUE;
}
case NPPM_INTERNAL_SWITCHVIEWFROMHWND:
{
HWND handle = reinterpret_cast<HWND>(lParam);
if (_mainEditView.getHSelf() == handle || _mainDocTab.getHSelf() == handle)
{
switchEditViewTo(MAIN_VIEW);
}
else if (_subEditView.getHSelf() == handle || _subDocTab.getHSelf() == handle)
{
switchEditViewTo(SUB_VIEW);
}
return TRUE;
}
case NPPM_INTERNAL_UPDATETITLEBAR:
{
setTitle();
return TRUE;
}
case NPPM_INTERNAL_CRLFFORMCHANGED:
{
_mainEditView.setCRLF();
_subEditView.setCRLF();
return TRUE;
}
case NPPM_INTERNAL_ENABLECHANGEHISTORY:
{
const ScintillaViewParams& svp = nppParam.getSVP();
int enabledCH = svp._isChangeHistoryEnabled ? (SC_CHANGE_HISTORY_ENABLED | SC_CHANGE_HISTORY_MARKERS) : SC_CHANGE_HISTORY_DISABLED;
_mainEditView.execute(SCI_SETCHANGEHISTORY, enabledCH);
_subEditView.execute(SCI_SETCHANGEHISTORY, enabledCH);
_mainEditView.showChangeHistoryMargin(svp._isChangeHistoryEnabled);
_subEditView.showChangeHistoryMargin(svp._isChangeHistoryEnabled);
return TRUE;
}
case NPPM_INTERNAL_CLEANBRACEMATCH:
{
_mainEditView.execute(SCI_SETHIGHLIGHTGUIDE, 0);
_subEditView.execute(SCI_SETHIGHLIGHTGUIDE, 0);
_mainEditView.execute(SCI_BRACEBADLIGHT, WPARAM(-1));
_subEditView.execute(SCI_BRACEBADLIGHT, WPARAM(-1));
return TRUE;
}
case NPPM_INTERNAL_CLEANSMARTHILITING:
{
_mainEditView.clearIndicator(SCE_UNIVERSAL_FOUND_STYLE_SMART);
_subEditView.clearIndicator(SCE_UNIVERSAL_FOUND_STYLE_SMART);
return TRUE;
}
case NPPM_INTERNAL_CRLFLAUNCHSTYLECONF:
{
// Launch _configStyleDlg (create or display it)
command(IDM_LANGSTYLE_CONFIG_DLG);
// go into the section we need
_configStyleDlg.goToSection(TEXT("Global Styles:EOL custom color"));
return TRUE;
}
case NPPM_INTERNAL_LAUNCHPREFERENCES:
{
// Launch _configStyleDlg (create or display it)
command(IDM_SETTING_PREFERENCE);
// go into the section we need
_preference.goToSection(wParam, lParam);
return TRUE;
}
case NPPM_INTERNAL_DISABLEAUTOUPDATE:
{
//printStr(TEXT("you've got me"));
NppGUI & nppGUI = nppParam.getNppGUI();
nppGUI._autoUpdateOpt._doAutoUpdate = false;
return TRUE;
}
case NPPM_GETLANGUAGENAME:
{
generic_string langName = getLangDesc((LangType)wParam, true);
if (lParam)
lstrcpy((LPTSTR)lParam, langName.c_str());
return langName.length();
}
case NPPM_GETLANGUAGEDESC:
{
generic_string langDesc = getLangDesc((LangType)wParam, false);
if (lParam)
lstrcpy((LPTSTR)lParam, langDesc.c_str());
return langDesc.length();
}
case NPPM_GETEXTERNALLEXERAUTOINDENTMODE:
{
int index = nppParam.getExternalLangIndexFromName(reinterpret_cast<TCHAR*>(wParam));
if (index < 0)
return FALSE;
*(reinterpret_cast<ExternalLexerAutoIndentMode*>(lParam)) = nppParam.getELCFromIndex(index)._autoIndentMode;
return TRUE;
}
case NPPM_SETEXTERNALLEXERAUTOINDENTMODE:
{
int index = nppParam.getExternalLangIndexFromName(reinterpret_cast<TCHAR*>(wParam));
if (index < 0)
return FALSE;
nppParam.getELCFromIndex(index)._autoIndentMode = static_cast<ExternalLexerAutoIndentMode>(lParam);
return TRUE;
}
case NPPM_ISAUTOINDENTON:
{
return nppParam.getNppGUI()._maitainIndent;
}
case NPPM_ISDARKMODEENABLED:
{
return NppDarkMode::isEnabled();
}
case NPPM_GETDARKMODECOLORS:
{
if (static_cast<size_t>(wParam) != sizeof(NppDarkMode::Colors))
return static_cast<LRESULT>(false);
NppDarkMode::Colors* currentColors = reinterpret_cast<NppDarkMode::Colors*>(lParam);
if (currentColors != NULL)
{
currentColors->background = NppDarkMode::getBackgroundColor();
currentColors->softerBackground = NppDarkMode::getSofterBackgroundColor();
currentColors->hotBackground = NppDarkMode::getHotBackgroundColor();
currentColors->pureBackground = NppDarkMode::getDarkerBackgroundColor();
currentColors->errorBackground = NppDarkMode::getErrorBackgroundColor();
currentColors->text = NppDarkMode::getTextColor();
currentColors->darkerText = NppDarkMode::getDarkerTextColor();
currentColors->disabledText = NppDarkMode::getDisabledTextColor();
currentColors->linkText = NppDarkMode::getLinkTextColor();
currentColors->edge = NppDarkMode::getEdgeColor();
currentColors->hotEdge = NppDarkMode::getHotEdgeColor();
currentColors->disabledEdge = NppDarkMode::getDisabledEdgeColor();
return static_cast<LRESULT>(true);
}
return static_cast<LRESULT>(false);
}
case NPPM_DOCLISTDISABLEPATHCOLUMN:
case NPPM_DOCLISTDISABLEEXTCOLUMN:
{
BOOL isOff = static_cast<BOOL>(lParam);
NppGUI & nppGUI = nppParam.getNppGUI();
if (message == NPPM_DOCLISTDISABLEEXTCOLUMN)
nppGUI._fileSwitcherWithoutExtColumn = isOff == TRUE;
else
nppGUI._fileSwitcherWithoutPathColumn = isOff == TRUE;
if (_pDocumentListPanel)
{
_pDocumentListPanel->reload();
}
// else nothing to do
return TRUE;
}
case NPPM_GETEDITORDEFAULTFOREGROUNDCOLOR:
case NPPM_GETEDITORDEFAULTBACKGROUNDCOLOR:
{
return (message == NPPM_GETEDITORDEFAULTFOREGROUNDCOLOR
?(NppParameters::getInstance()).getCurrentDefaultFgColor()
:(NppParameters::getInstance()).getCurrentDefaultBgColor());
}
case NPPM_SHOWDOCLIST:
{
BOOL toShow = static_cast<BOOL>(lParam);
if (toShow)
{
if (!_pDocumentListPanel || !_pDocumentListPanel->isVisible())
launchDocumentListPanel();
}
else
{
if (_pDocumentListPanel)
_pDocumentListPanel->display(false);
}
return TRUE;
}
case NPPM_ISDOCLISTSHOWN:
{
if (!_pDocumentListPanel)
return FALSE;
return _pDocumentListPanel->isVisible();
}
// OLD BEHAVIOUR:
// if doLocal, it's always false - having doLocal environment cannot load plugins outside
// the presence of file "allowAppDataPlugins.xml" will be checked only when not doLocal
//
// NEW BEHAVIOUR:
// No more file "allowAppDataPlugins.xml"
// if doLocal - not allowed. Otherwise - allowed.
case NPPM_GETAPPDATAPLUGINSALLOWED:
{
const TCHAR *appDataNpp = nppParam.getAppDataNppDir();
if (appDataNpp[0]) // if not doLocal
{
return TRUE;
}
return FALSE;
}
case NPPM_REMOVESHORTCUTBYCMDID:
{
int cmdID = static_cast<int32_t>(wParam);
return _pluginsManager.removeShortcutByCmdID(cmdID);
}
//
// These are sent by Preferences Dialog
//
case NPPM_INTERNAL_SETTING_HISTORY_SIZE:
{
_lastRecentFileList.setUserMaxNbLRF(nppParam.getNbMaxRecentFile());
break;
}
case NPPM_INTERNAL_EDGEMULTISETSIZE:
{
_mainEditView.execute(SCI_MULTIEDGECLEARALL);
_subEditView.execute(SCI_MULTIEDGECLEARALL);
ScintillaViewParams &svp = const_cast<ScintillaViewParams &>(nppParam.getSVP());
COLORREF multiEdgeColor = liteGrey;
const Style * pStyle = NppParameters::getInstance().getMiscStylerArray().findByName(TEXT("Edge colour"));
if (pStyle)
{
multiEdgeColor = pStyle->_fgColor;
}
const size_t twoPower13 = 8192;
size_t nbColAdded = 0;
for (auto i : svp._edgeMultiColumnPos)
{
// it's absurd to set columns beyon 8000, even it's a long line.
// So let's ignore all the number greater than 2^13
if (i > twoPower13)
continue;
_mainEditView.execute(SCI_MULTIEDGEADDLINE, i, multiEdgeColor);
_subEditView.execute(SCI_MULTIEDGEADDLINE, i, multiEdgeColor);
++nbColAdded;
}
int mode;
switch (nbColAdded)
{
case 0:
{
mode = EDGE_NONE;
break;
}
case 1:
{
if (svp._isEdgeBgMode)
{
mode = EDGE_BACKGROUND;
_mainEditView.execute(SCI_SETEDGECOLUMN, svp._edgeMultiColumnPos[0]);
_subEditView.execute(SCI_SETEDGECOLUMN, svp._edgeMultiColumnPos[0]);
}
else
{
mode = EDGE_MULTILINE;
}
break;
}
default:
mode = EDGE_MULTILINE;
}
_mainEditView.execute(SCI_SETEDGEMODE, mode);
_subEditView.execute(SCI_SETEDGEMODE, mode);
}
break;
case NPPM_INTERNAL_SETTING_TAB_REPLCESPACE:
case NPPM_INTERNAL_SETTING_TAB_SIZE:
{
_pEditView->setTabSettings(_pEditView->getCurrentBuffer()->getCurrentLang());
break;
}
case NPPM_INTERNAL_RECENTFILELIST_UPDATE:
{
_lastRecentFileList.updateMenu();
break;
}
case NPPM_INTERNAL_RECENTFILELIST_SWITCH:
{
_lastRecentFileList.switchMode();
_lastRecentFileList.updateMenu();
break;
}
case WM_INITMENUPOPUP:
{
_windowsMenu.initPopupMenu(reinterpret_cast<HMENU>(wParam), _pDocTab);
return TRUE;
}
case WM_ENTERMENULOOP:
{
const NppGUI & nppgui = nppParam.getNppGUI();
if (!nppgui._menuBarShow && !wParam && !_sysMenuEntering)
::SetMenu(hwnd, _mainMenuHandle);
return TRUE;
}
case WM_EXITMENULOOP:
{
const NppGUI & nppgui = nppParam.getNppGUI();
if (!nppgui._menuBarShow && !wParam && !_sysMenuEntering)
::SetMenu(hwnd, NULL);
_sysMenuEntering = false;
return FALSE;
}
case WM_DPICHANGED:
{
return TRUE;
}
case NPPM_INTERNAL_UPDATECLICKABLELINKS:
{
ScintillaEditView* pView = reinterpret_cast<ScintillaEditView*>(wParam);
if (pView == NULL)
{
addHotSpot(_pEditView);
addHotSpot(_pNonEditView);
}
else
{
addHotSpot(pView);
}
}
case NPPM_INTERNAL_UPDATETEXTZONEPADDING:
{
ScintillaViewParams &svp = const_cast<ScintillaViewParams &>(nppParam.getSVP());
if (_beforeSpecialView._isDistractionFree)
{
int paddingLen = svp.getDistractionFreePadding(_pEditView->getWidth());
_pEditView->execute(SCI_SETMARGINLEFT, 0, paddingLen);
_pEditView->execute(SCI_SETMARGINRIGHT, 0, paddingLen);
}
else
{
_mainEditView.execute(SCI_SETMARGINLEFT, 0, svp._paddingLeft);
_mainEditView.execute(SCI_SETMARGINRIGHT, 0, svp._paddingRight);
_subEditView.execute(SCI_SETMARGINLEFT, 0, svp._paddingLeft);
_subEditView.execute(SCI_SETMARGINRIGHT, 0, svp._paddingRight);
}
return TRUE;
}
case NPPM_INTERNAL_REFRESHWORKDIR:
{
const Buffer* buf = _pEditView->getCurrentBuffer();
generic_string path = buf ? buf->getFullPathName() : _T("");
PathRemoveFileSpec(path);
setWorkingDir(path.c_str());
return TRUE;
}
default:
{
if (message == WDN_NOTIFY)
{
NMWINDLG* nmdlg = reinterpret_cast<NMWINDLG*>(lParam);
switch (nmdlg->type)
{
case WDT_ACTIVATE:
{
activateDoc(nmdlg->curSel);
nmdlg->processed = TRUE;
break;
}
case WDT_SAVE:
{
//loop through nmdlg->nItems, get index and save it
for (unsigned int i = 0; i < nmdlg->nItems; ++i)
{
fileSave(_pDocTab->getBufferByIndex(nmdlg->Items[i]));
}
nmdlg->processed = TRUE;
break;
}
case WDT_CLOSE:
{
//loop through nmdlg->nItems, get index and close it
for (unsigned int i = 0; i < nmdlg->nItems; ++i)
{
bool closed = fileClose(_pDocTab->getBufferByIndex(nmdlg->Items[i]), currentView());
UINT pos = nmdlg->Items[i];
// The window list only needs to be rearranged when the file was actually closed
if (closed)
{
nmdlg->Items[i] = 0xFFFFFFFF; // indicate file was closed
// Shift the remaining items downward to fill the gap
for (unsigned int j = i + 1; j < nmdlg->nItems; ++j)
{
if (nmdlg->Items[j] > pos)
nmdlg->Items[j]--;
}
}
}
nmdlg->processed = TRUE;
break;
}
case WDT_SORT:
{
if (nmdlg->nItems != _pDocTab->nbItem()) //sanity check, if mismatch just abort
break;
//Collect all buffers
std::vector<BufferID> tempBufs;
for (unsigned int i = 0; i < nmdlg->nItems; ++i)
{
tempBufs.push_back(_pDocTab->getBufferByIndex(i));
}
//Reset buffers
for (unsigned int i = 0; i < nmdlg->nItems; ++i)
{
_pDocTab->setBuffer(i, tempBufs[nmdlg->Items[i]]);
}
activateBuffer(_pDocTab->getBufferByIndex(_pDocTab->getCurrentTabIndex()), currentView());
::SendMessage(_pDocTab->getHParent(), NPPM_INTERNAL_DOCORDERCHANGED, 0, _pDocTab->getCurrentTabIndex());
break;
}
}
return TRUE;
}
return ::DefWindowProc(hwnd, message, wParam, lParam);
}
}
_pluginsManager.relayNppMessages(message, wParam, lParam);
return result;
}