mirror of
https://github.com/cxasm/notepad--.git
synced 2026-10-20 00:09:43 +08:00
472 lines
13 KiB
C++
Executable File
472 lines
13 KiB
C++
Executable File
#include "ccnotepad.h"
|
|
#include "nddsetting.h"
|
|
#include "styleset.h"
|
|
|
|
|
|
#include <QtWidgets/QApplication>
|
|
#include <QTextCodec>
|
|
#include <QMessageBox>
|
|
#include <QSharedMemory>
|
|
#include <QFile>
|
|
#include <QStatusBar>
|
|
#include <qobject.h>
|
|
#include <QThread>
|
|
#include <QDir>
|
|
|
|
#ifdef Q_OS_UNIX
|
|
#include <QStyleFactory>
|
|
#include <signal.h>
|
|
#include <unistd.h>
|
|
#include <QDebug>
|
|
#include <QWidget>
|
|
#endif
|
|
|
|
#ifdef Q_OS_WIN
|
|
#pragma comment(lib, "user32.lib")
|
|
#if _DEBUG
|
|
#pragma comment(lib, "qmyedit_qt5d.lib")
|
|
#else
|
|
#pragma comment(lib, "qmyedit_qt5.lib")
|
|
#endif
|
|
#include <qt_windows.h>
|
|
const ULONG_PTR CUSTOM_TYPE = 10000;
|
|
const ULONG_PTR OPEN_NOTEPAD_TYPE = 10001;
|
|
const ULONG_PTR CUSTOM_TYPE_FILE_LINENUM = 10002;
|
|
bool s_isAdminAuth = false;
|
|
#endif
|
|
|
|
const QString c_strTitle = "Ndd";
|
|
|
|
|
|
#ifdef Q_OS_UNIX
|
|
#if defined(Q_OS_MAC)
|
|
QSharedMemory shared("CCNotebook123");;//mac下面后面带一个版本号,避免新的打不开
|
|
#else
|
|
QSharedMemory shared("CCNotebook");
|
|
#endif
|
|
QSharedMemory nppShared("notepad--");
|
|
|
|
static void sig_usr(int signo)
|
|
{
|
|
if(signo == SIGUSR1)
|
|
{
|
|
qlonglong winId;
|
|
shared.lock();
|
|
memcpy(&winId,shared.data(),sizeof(qlonglong));
|
|
shared.unlock();
|
|
|
|
QWidget *pMain = QWidget::find((WId)winId);
|
|
CCNotePad* pNotePad = dynamic_cast<CCNotePad*>(pMain);
|
|
if(pNotePad != nullptr)
|
|
{
|
|
QString filePath((char*)nppShared.data()+4);
|
|
if(!filePath.isEmpty())
|
|
{
|
|
pNotePad->openFile(filePath);
|
|
}
|
|
pNotePad->activateWindow();
|
|
pNotePad->showNormal();
|
|
qDebug() << "sig_usr" << filePath;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef Q_OS_MAC
|
|
|
|
static void openfile(QString filePath)
|
|
{
|
|
|
|
qlonglong winId;
|
|
shared.lock();
|
|
memcpy(&winId,shared.data(),sizeof(qlonglong));
|
|
shared.unlock();
|
|
|
|
QWidget *pMain = QWidget::find((WId)winId);
|
|
CCNotePad* pNotePad = dynamic_cast<CCNotePad*>(pMain);
|
|
if(pNotePad != nullptr)
|
|
{
|
|
if(!filePath.isEmpty())
|
|
{
|
|
pNotePad->openFile(filePath);
|
|
}
|
|
pNotePad->activateWindow();
|
|
pNotePad->showNormal();
|
|
}
|
|
}
|
|
|
|
class MyApplication : public QApplication
|
|
{
|
|
public:
|
|
MyApplication(int &argc, char **argv)
|
|
: QApplication(argc, argv)
|
|
{
|
|
}
|
|
|
|
bool event(QEvent *event)
|
|
{
|
|
if (event->type() == QEvent::FileOpen) {
|
|
QFileOpenEvent *openEvent = static_cast<QFileOpenEvent *>(event);
|
|
qDebug() << "Open file" << openEvent->file();
|
|
s_openfile = openEvent->file();
|
|
openfile(s_openfile);
|
|
}
|
|
|
|
return QApplication::event(event);
|
|
}
|
|
QString s_openfile;
|
|
};
|
|
#endif
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
//可以防止某些屏幕下的字体拥挤重叠问题。暂时屏蔽,不使用qt方法,使用windows自带方案
|
|
// 发现windows自带方案模糊。//发现下面打开后,在win10上反而效果不好,界面会变得很大,默认还是不开启的好。
|
|
//QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
|
//QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
|
|
//QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::RoundPreferFloor);
|
|
|
|
#ifdef Q_OS_MAC
|
|
MyApplication a(argc, argv);
|
|
#else
|
|
QApplication a(argc, argv);
|
|
#endif
|
|
|
|
//不能开启,开启后相对路径打开文件失败
|
|
//QDir::setCurrent(QCoreApplication::applicationDirPath());
|
|
|
|
#if defined(Q_OS_UNIX)
|
|
QApplication::setStyle(QStyleFactory::create("fusion"));
|
|
#endif
|
|
a.setApplicationDisplayName(c_strTitle);
|
|
a.setApplicationName(c_strTitle);
|
|
|
|
QStringList arguments = QCoreApplication::arguments();
|
|
|
|
//目前就三种
|
|
//1) ndd filepath
|
|
//2) ndd filepath -n linenum
|
|
//3) ndd -multi filepath
|
|
//只有 1 2 需要处理短路径
|
|
if ((arguments.size() == 2) || (arguments.size() == 4))
|
|
{
|
|
QFileInfo fi(arguments[1]);
|
|
if (fi.isRelative())
|
|
{
|
|
QString absDir = QDir::currentPath();
|
|
//获取绝对路径
|
|
arguments[1] = QString("%1/%2").arg(absDir).arg(arguments.at(1));
|
|
}
|
|
}
|
|
|
|
#ifdef uos
|
|
QFont font("Noto Sans CJK SC,9,-1,5,50,0,0,0,0,0,Regular", 9);
|
|
QApplication::setFont(font);
|
|
#endif
|
|
#ifdef Q_OS_MAC
|
|
//这里的字体大小,务必要和查找结果框的高度匹配,否则会结构字体拥挤
|
|
QFont font("Courier New,11,-1,5,50,0,0,0,0,0,Regular", 11);
|
|
// qDebug() << "font name mac";
|
|
QApplication::setFont(font);
|
|
// qDebug() << QApplication::font().toString();
|
|
#endif
|
|
|
|
bool isGotoLine = false;
|
|
|
|
#ifdef Q_OS_WIN
|
|
QSharedMemory shared("ccnotepad");
|
|
|
|
if (arguments.size() > 2)
|
|
{
|
|
//如果是多开请求,这种是从管理员权限申请后重开过来的
|
|
if (arguments[1] == QString("-muti"))
|
|
{
|
|
s_isAdminAuth = true;
|
|
|
|
QString title = QString(u8"%1 管理员").arg(c_strTitle);
|
|
a.setApplicationDisplayName(title);
|
|
//删除-muti这个参数
|
|
arguments.removeAt(1);
|
|
|
|
//管理员不占用共享标志。这样的目的是,当管理员窗口存在时
|
|
//打开原来的文件,原来的文件可以占用共享标志,作为主窗口打开。
|
|
//管理员窗口永远不做主窗口打开
|
|
goto authAdmin;
|
|
|
|
}
|
|
else if ((arguments.size() == 4) && arguments[2] == QString("-n"))
|
|
{
|
|
//使用的是 file -n lineNums 方式。目前只有windows下支持 xxxfile -n linenum的格式
|
|
isGotoLine = true;
|
|
}
|
|
|
|
}
|
|
#else
|
|
if ((arguments.size() == 4) && (arguments[2] == QString("-n")))
|
|
{
|
|
//使用的是 file -n lineNums 方式。目前只有windows下支持 xxxfile -n linenum的格式
|
|
isGotoLine = true;
|
|
}
|
|
#endif
|
|
|
|
//attach成功表示已经存在该内存了,表示当前存在实例
|
|
if (shared.attach())//共享内存被占用则直接返回
|
|
{
|
|
//发现在文件中如果存在空格时,参数不止1个,所以不能单纯用2个参数表示
|
|
if (arguments.size() > 1)
|
|
{
|
|
#if defined(Q_OS_WIN)
|
|
int tryTimes = 0;
|
|
do {
|
|
qlonglong hwndId;
|
|
shared.lock();
|
|
memcpy(&hwndId, shared.data(), sizeof(qlonglong));
|
|
shared.unlock();
|
|
|
|
HWND hwnd = (HWND)hwndId;
|
|
|
|
if (::IsWindow(hwnd))
|
|
{
|
|
if (!isGotoLine)
|
|
{
|
|
//就是ndd filepath的命令行格式
|
|
//去掉第一个参数,后续的参数拼接起来。其实参数中间有空格还是需要使用""引用起来,避免空格参数分隔为多个
|
|
arguments.takeFirst();
|
|
|
|
QString filename = arguments.join("");
|
|
QByteArray data = filename.toUtf8();
|
|
|
|
COPYDATASTRUCT copydata;
|
|
copydata.dwData = CUSTOM_TYPE; //自定义类型
|
|
copydata.lpData = data.data(); //数据大小
|
|
copydata.cbData = data.size(); // 指向数据的指针
|
|
|
|
::SendMessage(hwnd, WM_COPYDATA, reinterpret_cast<WPARAM>(nullptr), reinterpret_cast<LPARAM>(©data));
|
|
}
|
|
else
|
|
{
|
|
//是 filepath -n linenums 方式。不考虑filepath含有空格的情况,因为前面做了严格判断
|
|
|
|
QString para = QString("%1|%2").arg(arguments[1]).arg(arguments[3]);
|
|
QByteArray data = para.toUtf8();
|
|
|
|
COPYDATASTRUCT copydata;
|
|
copydata.dwData = CUSTOM_TYPE_FILE_LINENUM; //自定义类型
|
|
copydata.lpData = data.data(); //数据大小
|
|
copydata.cbData = data.size(); // 指向数据的指针
|
|
|
|
::SendMessage(hwnd, WM_COPYDATA, reinterpret_cast<WPARAM>(nullptr), reinterpret_cast<LPARAM>(©data));
|
|
}
|
|
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
|
|
//20230304 右键多个文件同时打开,比如3个。此时只有第1个可获取锁,其余2个均走这里。
|
|
//因为第个还没有来的及写入hwnd。此时不要goto drop_old。等一下再重试
|
|
QThread::sleep(1);
|
|
++tryTimes;
|
|
|
|
//2次识别后,没法了,只能通过继续往下走。
|
|
//失败了,此时说明前一个窗口极可能状态错误了。如果不处理,则再也打不开程序了
|
|
if (tryTimes > 2)
|
|
{
|
|
goto drop_old;
|
|
}
|
|
|
|
}
|
|
} while (true);
|
|
|
|
#elif defined (Q_OS_MAC)
|
|
{
|
|
//mac下面不需要,有他自身的机制保证
|
|
}
|
|
#else
|
|
pid_t pid;
|
|
|
|
arguments.takeFirst();
|
|
QString filename = arguments.join("");
|
|
QByteArray data = filename.toUtf8();
|
|
|
|
nppShared.attach();
|
|
nppShared.lock();
|
|
memcpy(&pid, nppShared.data(), sizeof(pid_t));
|
|
memset((char*)nppShared.data()+sizeof(pid_t),0, 1024-sizeof(pid_t));
|
|
memcpy((char*)nppShared.data()+sizeof(pid_t),data.data(),data.size());
|
|
nppShared.unlock();
|
|
|
|
//if kill failed, then open a new process
|
|
if(0 != kill(pid,SIGUSR1))
|
|
{
|
|
goto unix_goon;
|
|
}
|
|
#endif
|
|
}
|
|
else if (arguments.size() == 1)
|
|
{
|
|
#if defined(Q_OS_WIN)
|
|
//把窗口设置到最前
|
|
qlonglong hwndId;
|
|
shared.lock();
|
|
memcpy(&hwndId, shared.data(), sizeof(qlonglong));
|
|
shared.unlock();
|
|
HWND hwnd = (HWND)hwndId;
|
|
if (::IsWindow(hwnd))
|
|
{
|
|
QString filename("open");
|
|
QByteArray data = filename.toUtf8();
|
|
|
|
COPYDATASTRUCT copydata;
|
|
copydata.dwData = OPEN_NOTEPAD_TYPE; //自定义类型
|
|
copydata.lpData = data.data(); //数据大小
|
|
copydata.cbData = data.size(); // 指向数据的指针
|
|
|
|
::SendMessage(hwnd, WM_COPYDATA, reinterpret_cast<WPARAM>(nullptr), reinterpret_cast<LPARAM>(©data));
|
|
}
|
|
else
|
|
{
|
|
//失败了,此时说明前一个窗口极可能状态错误了。如果不处理,则再也打不开程序了
|
|
//继续新开一个窗口,放弃之前的旧内容
|
|
goto drop_old;
|
|
}
|
|
#elif defined (Q_OS_MAC)
|
|
{
|
|
//mac下面不需要,有他自身的机制保证
|
|
}
|
|
#else
|
|
pid_t pid;
|
|
nppShared.attach();
|
|
nppShared.lock();
|
|
memcpy(&pid, nppShared.data(), sizeof(pid_t));
|
|
memset((char*)nppShared.data()+sizeof(pid_t),0, 1024-sizeof(pid_t));
|
|
nppShared.unlock();
|
|
qDebug()<<"empty file send";
|
|
|
|
if(0 != kill(pid,SIGUSR1))
|
|
{
|
|
goto unix_goon;
|
|
}
|
|
#endif
|
|
}
|
|
return 0;
|
|
}
|
|
#if defined(Q_OS_WIN)
|
|
shared.create(32);
|
|
#elif defined (Q_OS_MAC)
|
|
{
|
|
//mac下面不需要,有他自身的机制保证。当程序已经在线时,再打开程序,系统会自动调用已经存在的程序出现
|
|
//不需要使用类似linux下面的机制。
|
|
shared.create(32);
|
|
nppShared.create(32);
|
|
}
|
|
#else
|
|
|
|
unix_goon:
|
|
shared.create(32);
|
|
nppShared.create(2048);
|
|
|
|
if(signal(SIGUSR1,sig_usr) == SIG_ERR)
|
|
{
|
|
qDebug()<<"linux create sign failed";
|
|
}
|
|
#endif
|
|
|
|
#if defined(Q_OS_WIN)
|
|
authAdmin:
|
|
drop_old:
|
|
#endif
|
|
|
|
//20221009发现有小概率出现窗口没有,但是进程还在的诡异问题,加个保护一下
|
|
QApplication::setQuitOnLastWindowClosed(true);
|
|
|
|
NddSetting::init();
|
|
|
|
int id = NddSetting::getKeyValueFromNumSets(SKIN_KEY);
|
|
StyleSet::setSkin(id);
|
|
|
|
CCNotePad *pMainNotepad = new CCNotePad(true);
|
|
pMainNotepad->setAttribute(Qt::WA_DeleteOnClose);
|
|
pMainNotepad->setShareMem(&shared);
|
|
pMainNotepad->quickshow();
|
|
|
|
pMainNotepad->syncCurSkinToMenu(id);
|
|
|
|
|
|
#ifdef Q_OS_WIN
|
|
//HWND hwnd = ::FindWindowA("Qt5QWindowIcon", "CCNotebook");
|
|
//发现hwnd就是和effectiveWinId相等的,不需要查询了
|
|
//管理员可以多开,暂时不把管理员的权限作为主窗口,因为其他用户没有权限右键菜单发送消息给管理员窗口去打开文件
|
|
if (!s_isAdminAuth)
|
|
{
|
|
qlonglong winId = (qlonglong)pMainNotepad->effectiveWinId();
|
|
shared.lock();
|
|
memcpy(shared.data(), &winId, sizeof(qlonglong));
|
|
shared.unlock();
|
|
}
|
|
#else
|
|
qlonglong winId = (qlonglong)pMainNotepad->effectiveWinId();
|
|
shared.lock();
|
|
memcpy(shared.data(), &winId, sizeof(qlonglong));
|
|
shared.unlock();
|
|
nppShared.attach();
|
|
//get proceess id to share memory
|
|
pid_t pid = getpid();
|
|
nppShared.lock();
|
|
memcpy(nppShared.data(), &pid, sizeof(pid_t));
|
|
nppShared.unlock();
|
|
#endif // Q_OS_WIN
|
|
//恢复上次关闭时的文件
|
|
#ifdef Q_OS_WIN
|
|
if (!s_isAdminAuth)
|
|
{
|
|
if (0 == pMainNotepad->restoreLastFiles() && (arguments.size() == 1))
|
|
{
|
|
pMainNotepad->initTabNewOne();
|
|
}
|
|
}
|
|
#else
|
|
if (0 == pMainNotepad->restoreLastFiles())
|
|
{
|
|
pMainNotepad->initTabNewOne();
|
|
}
|
|
#endif
|
|
if (arguments.size() == 2)
|
|
{
|
|
#ifdef Q_OS_WIN
|
|
if (!s_isAdminAuth)
|
|
{
|
|
pMainNotepad->openFile(arguments[1]);
|
|
}
|
|
else
|
|
{
|
|
//如果是管理员,还不能直接打开文件,需要恢复之前文件的修改内容
|
|
//恢复不了,再直接打开
|
|
pMainNotepad->tryRestoreFile(arguments[1]);
|
|
}
|
|
#else
|
|
pMainNotepad->openFile(arguments[1]);
|
|
#endif
|
|
}
|
|
else if (isGotoLine)
|
|
{
|
|
//是filepath -n xxx 格式。
|
|
bool ok = true;
|
|
int lineNum = arguments[3].toInt(&ok);
|
|
if (!ok)
|
|
{
|
|
lineNum = -1;
|
|
}
|
|
pMainNotepad->openFile(arguments[1], lineNum);
|
|
}
|
|
#ifdef Q_OS_WIN
|
|
pMainNotepad->checkAppFont();
|
|
#endif
|
|
|
|
a.exec();
|
|
|
|
NddSetting::close();
|
|
|
|
return 0;
|
|
}
|