-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.cpp
More file actions
82 lines (71 loc) · 3.65 KB
/
Copy pathmain.cpp
File metadata and controls
82 lines (71 loc) · 3.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include "src/appsettings.h"
#include "src/breakscheduler.h"
#include "src/inputblocker.h"
#include "src/overlaycontroller.h"
#include "src/settingswindowmanager.h"
#include "src/trayicon.h"
#include <QApplication>
#include <QQmlApplicationEngine>
#include <QSharedMemory>
#include <QSystemTrayIcon>
#include <QTimer>
int main(int argc, char *argv[])
{
// 托盘依赖 QtWidgets(Qt Quick 无原生托盘支持),因此用 QApplication
QApplication app(argc, argv);
QApplication::setApplicationName(QStringLiteral("ForcedBreak"));
QApplication::setOrganizationName(QStringLiteral("ForcedBreak"));
// 没有主窗口,设置窗口关闭后不应退出程序
QApplication::setQuitOnLastWindowClosed(false);
// 设置窗口等顶层窗口的标题栏/任务栏图标(exe 自身的图标由 assets/app.rc 提供)
QApplication::setWindowIcon(TrayIcon::appIcon());
// 单实例保护:两份程序会产生两套互相冲突的计时器
QSharedMemory singleInstance(QStringLiteral("ForcedBreak-SingleInstance"));
if (!singleInstance.create(1)) {
// 弹一条气泡提示后静默退出,不重复驻留
QSystemTrayIcon notice(TrayIcon::appIcon());
notice.show();
notice.showMessage(QObject::tr("ForcedBreak"), QObject::tr("ForcedBreak 已在运行中。"));
QTimer::singleShot(3000, &app, &QCoreApplication::quit);
return QApplication::exec();
}
QQmlApplicationEngine engine;
auto *settings = engine.singletonInstance<AppSettings *>("ForcedBreak", "AppSettings");
auto *scheduler = engine.singletonInstance<BreakScheduler *>("ForcedBreak", "BreakScheduler");
if (!settings || !scheduler) {
qCritical("QML 单例注册失败,无法启动");
return -1;
}
OverlayController overlays(&engine);
InputBlocker blocker;
SettingsWindowManager settingsWindow(&engine);
TrayIcon tray(settings, scheduler, &app);
// 休息开始:装遮罩 + 上钩子;结束:反向拆除
QObject::connect(scheduler, &BreakScheduler::breakStarted, &app, [&](int) {
overlays.showOverlays();
blocker.engage();
});
QObject::connect(scheduler, &BreakScheduler::breakEnded, &app, [&] {
blocker.disengage();
overlays.hideOverlays();
});
QObject::connect(&blocker, &InputBlocker::focusStealRequested,
&overlays, &OverlayController::raiseOverlays);
// 快到点时用托盘气泡提前打个招呼,让用户有时间收尾手头的事
QObject::connect(scheduler, &BreakScheduler::preBreakNotice, &app, [&](int remainSec) {
const int minutes = remainSec / 60;
const QString when = minutes > 0 ? QObject::tr("%1 分钟").arg(minutes)
: QObject::tr("%1 秒").arg(remainSec);
tray.showMessage(QObject::tr("ForcedBreak"),
QObject::tr("还有 %1 就要开始休息了,请准备收尾。").arg(when));
});
QObject::connect(&tray, &TrayIcon::breakNowRequested, scheduler, &BreakScheduler::triggerBreakNow);
QObject::connect(&tray, &TrayIcon::resetRequested, scheduler, &BreakScheduler::resetTimer);
QObject::connect(&tray, &TrayIcon::enabledToggled, scheduler, &BreakScheduler::setEnabled);
QObject::connect(&tray, &TrayIcon::pauseToggled, scheduler, &BreakScheduler::setPaused);
QObject::connect(&tray, &TrayIcon::settingsRequested, &settingsWindow, &SettingsWindowManager::open);
QObject::connect(&tray, &TrayIcon::quitRequested, &app, &QCoreApplication::quit);
// 总开关默认关闭,不在此处启动计时——由用户从托盘菜单开启
tray.show();
return QApplication::exec();
}