-
Notifications
You must be signed in to change notification settings - Fork 0
/
dapplication.cpp
1173 lines (1000 loc) · 39.8 KB
/
dapplication.cpp
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* Copyright (C) 2015 ~ 2017 Deepin Technology Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* 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 Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <QtGlobal>
#ifdef Q_OS_LINUX
#ifdef private
#undef private
#endif
#define private public
#include <QWidget>
#undef private
#endif
#include <QDebug>
#include <QDir>
#include <QLocalSocket>
#include <QLibraryInfo>
#include <QTranslator>
#include <QLocalServer>
#include <QPixmapCache>
#include <QProcess>
#include <QMenu>
#include <QStyleFactory>
#include <QSystemSemaphore>
#include <QtConcurrent/QtConcurrent>
#include <qpa/qplatformintegrationfactory_p.h>
#include <private/qwidget_p.h>
#include <DStandardPaths>
#ifdef Q_OS_UNIX
#include <unistd.h>
#endif
#include "custom_dapplication.h"
#include <dthememanager.h>
#include "private/dapplication_p.h"
#include <daboutdialog.h>
#include <dmainwindow.h>
#include <DPlatformHandle>
#include <DGuiApplicationHelper>
#ifdef Q_OS_UNIX
#include <QDBusError>
#include <QDBusReply>
#include <QDBusInterface>
#include <QDBusPendingCall>
#include <QDBusConnection>
#endif
#ifdef Q_OS_LINUX
#include "private/startupnotifications/startupnotificationmonitor.h"
#include <DDBusSender>
#include <QGSettings>
#endif
#define DXCB_PLUGIN_KEY "dxcb"
#define DXCB_PLUGIN_SYMBOLIC_PROPERTY "_d_isDxcb"
#define QT_THEME_CONFIG_PATH "D_QT_THEME_CONFIG_PATH"
DCORE_USE_NAMESPACE
DWIDGET_BEGIN_NAMESPACE
DApplicationPrivate::DApplicationPrivate(DApplication *q) :
DObjectPrivate(q)
{
#ifdef Q_OS_LINUX
StartupNotificationMonitor *monitor = StartupNotificationMonitor::instance();
auto cancelNotification = [this, q](const QString id) {
m_monitoredStartupApps.removeAll(id);
if (m_monitoredStartupApps.isEmpty()) {
q->restoreOverrideCursor();
}
};
QObject::connect(monitor, &StartupNotificationMonitor::appStartup,
q, [this, q, cancelNotification](const QString id) {
// FIX bug start app quikly cursor will not restore...
// Every setOverrideCursor() must eventually be followed by a corresponding restoreOverrideCursor(),
// otherwise the stack will never be emptied.
if (m_monitoredStartupApps.isEmpty()) {
q->setOverrideCursor(Qt::WaitCursor);
}
m_monitoredStartupApps.append(id);
// Set a timeout of 5s in case that some apps like pamac-tray started
// with StartupNotify but don't show a window after startup finished.
QTimer::singleShot(5 * 1000, q, [id, cancelNotification](){
cancelNotification(id);
});
});
QObject::connect(monitor, &StartupNotificationMonitor::appStartupCompleted,
q, cancelNotification);
#endif
QApplication::setStyle("chameleon");
}
DApplicationPrivate::~DApplicationPrivate()
{
if (m_localServer) {
m_localServer->close();
}
while (q_func()->overrideCursor()) {
q_func()->restoreOverrideCursor();
}
}
QString DApplicationPrivate::theme() const
{
return DThemeManager::instance()->theme();
}
void DApplicationPrivate::setTheme(const QString &theme)
{
DThemeManager *themeManager = DThemeManager::instance();
themeManager->setTheme(theme);
}
static bool tryAcquireSystemSemaphore(QSystemSemaphore *ss, qint64 timeout = 10)
{
if (ss->error() != QSystemSemaphore::NoError) {
return false;
}
QSystemSemaphore _tmp_ss(QString("%1-%2").arg("DTK::tryAcquireSystemSemaphore").arg(ss->key()), 1, QSystemSemaphore::Open);
_tmp_ss.acquire();
QElapsedTimer t;
QFuture<bool> request = QtConcurrent::run(ss, &QSystemSemaphore::acquire);
t.start();
while (Q_LIKELY(t.elapsed() < timeout && !request.isFinished()));
if (request.isFinished()) {
return true;
}
if (Q_LIKELY(request.isRunning())) {
if (Q_LIKELY(ss->release(1))) {
request.waitForFinished();
}
}
return false;
}
bool DApplicationPrivate::setSingleInstanceBySemaphore(const QString &key)
{
static QSystemSemaphore ss(key, 1, QSystemSemaphore::Open);
static bool singleInstance = false;
if (singleInstance) {
return true;
}
Q_ASSERT_X(ss.error() == QSystemSemaphore::NoError, "DApplicationPrivate::setSingleInstanceBySemaphore:", ss.errorString().toLocal8Bit().constData());
singleInstance = tryAcquireSystemSemaphore(&ss);
if (singleInstance) {
QtConcurrent::run([this] {
QPointer<DApplication> that = q_func();
while (ss.acquire() && singleInstance)
{
if (!that) {
return;
}
if (that->startingUp() || that->closingDown()) {
break;
}
ss.release(1);
if (that) {
Q_EMIT that->newInstanceStarted();
}
}
});
auto clean_fun = [] {
ss.release(1);
singleInstance = false;
};
qAddPostRoutine(clean_fun);
atexit(clean_fun);
}
return singleInstance;
}
#ifdef Q_OS_UNIX
/**
* \brief DApplicationPrivate::setSingleInstanceByDbus will check singleinstance by
* register dbus service
* \param key is the last of dbus service name, like "com.deepin.SingleInstance.key"
* \return
*/
bool DApplicationPrivate::setSingleInstanceByDbus(const QString &key)
{
auto basename = "com.deepin.SingleInstance.";
QString name = basename + key;
auto sessionBus = QDBusConnection::sessionBus();
if (!sessionBus.registerService(name)) {
qDebug() << "register service failed:" << sessionBus.lastError();
return false;
}
return true;
}
#endif
bool DApplicationPrivate::loadDtkTranslator(QList<QLocale> localeFallback)
{
D_Q(DApplication);
auto qtTranslator = new QTranslator(q);
qtTranslator->load("qt_" + QLocale::system().name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath));
q->installTranslator(qtTranslator);
auto qtbaseTranslator = new QTranslator(q);
qtTranslator->load("qtbase_" + QLocale::system().name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath));
q->installTranslator(qtbaseTranslator);
QList<DPathBuf> translateDirs;
//auto dtkwidgetDir = DWIDGET_TRANSLATIONS_DIR;
auto dtkwidgetName = "dtkwidget";
//("/home/user/.local/share", "/usr/local/share", "/usr/share")
auto dataDirs = DStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
for (const auto &path : dataDirs) {
DPathBuf DPathBuf(path);
//translateDirs << DPathBuf / dtkwidgetDir;
}
DPathBuf runDir(q->applicationDirPath());
translateDirs << runDir.join("translations");
DPathBuf currentDir(QDir::currentPath());
translateDirs << currentDir.join("translations");
#ifdef DTK_STATIC_TRANSLATION
translateDirs << DPathBuf(":/dtk/translations");
#endif
return loadTranslator(translateDirs, dtkwidgetName, localeFallback);
}
bool DApplicationPrivate::loadTranslator(QList<DPathBuf> translateDirs, const QString &name, QList<QLocale> localeFallback)
{
D_Q(DApplication);
QStringList missingQmfiles;
for (auto &locale : localeFallback) {
QString translateFilename = QString("%1_%2").arg(name).arg(locale.name());
for (auto &path : translateDirs) {
QString translatePath = (path / translateFilename).toString();
if (QFile::exists(translatePath + ".qm")) {
qDebug() << "load translate" << translatePath;
auto translator = new QTranslator(q);
translator->load(translatePath);
q->installTranslator(translator);
return true;
}
}
// fix english does not need to translation..
if (locale.language() != QLocale::English) {
missingQmfiles << translateFilename + ".qm";
}
QStringList parseLocalNameList = locale.name().split("_", QString::SkipEmptyParts);
if (parseLocalNameList.length() > 0) {
translateFilename = QString("%1_%2").arg(name)
.arg(parseLocalNameList.at(0));
for (auto &path : translateDirs) {
QString translatePath = (path / translateFilename).toString();
if (QFile::exists(translatePath + ".qm")) {
qDebug() << "translatePath after feedback:" << translatePath;
auto translator = new QTranslator(q);
translator->load(translatePath);
q->installTranslator(translator);
return true;
}
}
}
// fix english does not need to translation..
if (locale.language() != QLocale::English) {
missingQmfiles << translateFilename + ".qm";
}
}
if (missingQmfiles.size() > 0) {
qWarning() << name << "can not find qm files" << missingQmfiles;
}
return false;
}
// 自动激活DMainWindow类型的窗口
void DApplicationPrivate::_q_onNewInstanceStarted()
{
if (!autoActivateWindows)
return;
for (QWidget *window : qApp->topLevelWidgets()) {
if (qobject_cast<DSplitedWindow*>(window)) {
// 如果窗口最小化,應當先將其show出來
if (window->isMinimized())
window->showNormal();
window->activateWindow();
break; // 只激活找到的第一个窗口
}
}
}
bool DApplicationPrivate::isUserManualExists()
{
#ifdef Q_OS_LINUX
QDBusInterface manualSearch("com.deepin.Manual.Search",
"/com/deepin/Manual/Search",
"com.deepin.Manual.Search");
if (manualSearch.isValid()) {
QDBusReply<bool> reply = manualSearch.call("ManualExists", qApp->applicationName());
return reply.value();
} else {
const QString appName = qApp->applicationName();
bool dmanAppExists = QFile::exists("/usr/bin/dman");
bool dmanDataExists = QFile::exists("/usr/share/deepin-manual/manual/" + appName) ||
QFile::exists("/app/share/deepin-manual/manual/" + appName);
return dmanAppExists && dmanDataExists;
}
#else
return false;
#endif
}
/*!
* \~chinese \class DApplication
*
* \~chinese \brief DApplication 是 DTK 中用于替换 QCoreApplication 相关功能实现的类。
* \~chinese 继承自 QApplication ,并在此之上添加了一些特殊的设定,如:
* \~chinese - 在 FORCE_RASTER_WIDGETS 宏生效的情况下,默认设置 Qt::AA_ForceRasterWidgets 以减少 glx 相关库的加载,减少程序启动时间;
* \~chinese - 自动根据 applicationName 和 系统 locale 加载对应的翻译文件;
* \~chinese - 会根据系统gsettings中 com.deepin.dde.dapplication 的 qpixmapCacheLimit 值来设置 QPixmapCache::cacheLimit ;
* \~chinese - 会根据系统gsettings中 com.deepin.dde.touchscreen longpress-duration 的值来设置 QTapAndHoldGesture::timeout ;
* \~chinese - 方便地通过 setSingleInstance 来实现程序的单实例。
*
* \~chinese \note DApplication 设置的 QTapAndHoldGesture::timeout 会比 gsettings
* \~chinese 中的值小 100,用来绕过 Dock 长按松开容易导致应用启动的问题,详细解释见
* \~chinese 见代码注释或者 https://github.com/linuxdeepin/internal-discussion/issues/430
*
* \~chinese \sa loadTranslator, setSingleInstance.
*/
/*!
* \~chinese \fn DApplication::newInstanceStarted()
* \~chinese \brief newInstanceStarted 信号会在程序的一个新实例启动的时候被触发。
*
* \~chinese \fn DApplication::iconThemeChanged()
* \~chinese \brief iconThemeChanged 信号会在系统图标主题发生改变的时候被触发。
*
* \~chinese \fn DApplication::screenDevicePixelRatioChanged(QScreen *screen)
* \~chinese \brief screenDevicePixelRatioChanged 信号会在对应屏幕的缩放比可能发现变化
* \~chinese 时触发。
*
* \~chinese 依赖于 deepin 平台主题插件(dde-qt5integration 包中提供),实时更改
* \~chinese 屏幕缩放比是通过更改配置文件 ~/.config/deepin/qt-theme.ini 实现,与此相关的
* \~chinese 配置项有三个:
* \~chinese - ScreenScaleFactors:多屏幕设置不同缩放比,值格式和环境变量QT_SCREEN_SCALE_FACTORS一致
* \~chinese - ScaleFactor: 设置所有屏幕缩放比,值格式和环境变量QT_SCALE_FACTOR一致
* \~chinese - ScaleLogcailDpi:指定屏幕逻辑dpi,可影响仅设置了 point size 的 QFont 的绘制大小。
* \~chinese 未设置此值时,默认会在 \a ScreenScaleFactors 值改变后将屏幕逻辑dpi更改为主屏默认值,一般情况下,不需要设置此值。
* \~chinese \a ScreenScaleFactors 和 \a ScaleFactor 的值改变后,会触发所有屏幕的 QScreen::geometryChanged, 且会根据当前缩放
* \~chinese 更新所有QWindow的geometry(更新时保持窗口的真实大小不变,新窗口大小=窗口真实大小/新的缩放比)。另外,可在构造
* \~chinese DApplication 对象之前设置 \a Qt::AA_DisableHighDpiScaling 为 true,或添加环境变量 \a D_DISABLE_RT_SCREEN_SCALE
* \~chinese 禁用实时缩放的支持。
*
* \~chinese \sa QScreen::devicePixelRatio
*/
/**
* \~english @brief DApplication::DApplication constructs an instance of DApplication.
* \~english @param argc is the same as in the main function.
* \~english @param argv is the same as in the main function.
*
*
* \~chinese \brief DApplication::DApplication 用于构建 DApplication 实例的构造函数
*
* \~chinese 对象构造时会判断环境变量 DTK_FORCE_RASTER_WIDGETS 的值,如果为 TRUE 则开启
* \~chinese Qt::AA_ForceRasterWidgets,为 FALSE 则不开启,当没有设置此环境变量时,如果
* \~chinese 编译时使用了宏 FORCE_RASTER_WIDGETS(龙芯和申威平台默认使用),则开启
* \~chinese Qt::AA_ForceRasterWidgets,否则不开启。
* \~chinese \param argc 作用同 QApplication::QApplication 参数 argc。
* \~chinese \param argv 作用同 QApplication::QApplication 参数 argv。
*/
DApplication::DApplication(int &argc, char **argv) :
QApplication(argc, argv),
DObject(*new DApplicationPrivate(this))
{
qputenv("QT_QPA_PLATFORM", QByteArray());
// FIXME: fix bug in nvidia prime workaround, do not know effoct, must test more!!!
// 在龙芯和申威上,xcb插件中加载glx相关库(r600_dri.so等)会额外耗时1.xs(申威应该更长)
if (
#ifdef FORCE_RASTER_WIDGETS
QLatin1String("FALSE") !=
#else
QLatin1String("TRUE") ==
#endif
qgetenv("DTK_FORCE_RASTER_WIDGETS")) {
setAttribute(Qt::AA_ForceRasterWidgets);
}
#ifdef Q_OS_LINUX
// set qpixmap cache limit
if (QGSettings::isSchemaInstalled("com.deepin.dde.dapplication"))
{
QGSettings gsettings("com.deepin.dde.dapplication", "/com/deepin/dde/dapplication/");
if (gsettings.keys().contains("qpixmapCacheLimit"))
QPixmapCache::setCacheLimit(gsettings.get("qpixmap-cache-limit").toInt());
}
// set QTapAndHoldGesture::timeout
if (QGSettings::isSchemaInstalled("com.deepin.dde.touchscreen")) {
QGSettings gsettings("com.deepin.dde.touchscreen");
if (gsettings.keys().contains("longpressDuration"))
// NOTE(hualet): -100 is a workaround against the situation that that sometimes longpress
// and release on Dock cause App launches which should be avoided.
//
// I guess it happens like this: longpress happens on Dock,
// Dock menu shows(doesn't grab the mouse which is a bug can't be fixed easily),
// user ends the longpress, DDE Dock recevies mouseReleaseEvent and checks for
// QTapAndHoldGesture which is still not happening (maybe because the timer used is
// a CoarseTimer?), so Dock treats the event as a normal mouseReleaseEvent, launches the
// App or triggers the action.
//
// see: https://github.com/linuxdeepin/internal-discussion/issues/430
//
// This workaround hopefully can fix most of this situations.
QTapAndHoldGesture::setTimeout(gsettings.get("longpress-duration").toInt() - 100);
}
#endif
}
/*!
*
* \~chinese \enum DApplication::SingleScope
* \~chinese DApplication::SingleScope 定义了 DApplication 单实例的效应范围。
*
* \~chinese \var DApplication::SingleScope DApplication::UserScope
* \~chinese 代表单实例的范围为用户范围,即同一个用户会话中不允许其他实例出现。
*
* \~chinese \var DApplication::SingleScope DApplication::SystemScope
* \~chinese 代表单实例的范围为系统范围,当前系统内只允许一个程序实例运行。
*/
/**
* \~english @brief DApplication::theme returns name of the theme that the application is currently using.
*
* \~english theme name can be one of light, dark, semidark or semilight.
*
* \~english @return the theme name.
*
*
* \~chinese \property DApplication::theme
* \~chinese \brief theme 属性表示当前程序使用的主题名称,目前可选的主题名称有 light、dark、semidark 和 semilight。
*/
QString DApplication::theme() const
{
D_DC(DApplication);
return d->theme();
}
/**
* @brief DApplication::setTheme for the application to use the theme we provide.
* @param theme is the name of the theme we want to set.
*/
void DApplication::setTheme(const QString &theme)
{
D_D(DApplication);
d->setTheme(theme);
}
#ifdef Q_OS_UNIX
/*!
* @brief DApplication::setOOMScoreAdj set Out-Of-Memory score
* @param score vaild range is [-1000, 1000]
*
* \~chinese \brief DApplication::setOOMScoreAdj setOOMScoreAdj 用于调整当前进程的
* \~chinse Out-Of-Memory 分数(linux环境下),这个分数影响了内核在系统资源(内存)不足的
* \~chinse 情况下为了释放内存资源而挑选进程杀掉的算法,分数越高越容易被杀。
* \~chinese \param score 指定 oom-score,范围为 [-1000, 1000]。
*/
void DApplication::setOOMScoreAdj(const int score)
{
if (score > 1000 || score < -1000)
qWarning() << "OOM score adjustment value out of range: " << score;
QFile f("/proc/self/oom_score_adj");
if (!f.open(QIODevice::WriteOnly))
{
qWarning() << "OOM score adjust failed, open file error: " << f.errorString();
return;
}
f.write(std::to_string(score).c_str());
}
#endif
/**
* \~chinese \brief DApplication::setSingleInstance setSingleInstance 用于将程序
* \~chinese 设置成单实例。
* \~chinese \param key 是确定程序唯一性的ID,一般使用程序的二进制名称即可。
*
* \~chinese \note 一般情况下单实例的实现使用 QSystemSemaphore,如果你的程序需要在沙箱
* \~chinese 环境如 flatpak 中运行,可选的一套方案是通过 DTK_DBUS_SINGLEINSTANCE 这个
* \~chinese 编译宏来控制单实例使用 DBus 方案。
*
* \~chinese \return 设置成功返回 true,否则返回 false。
*/
bool DApplication::setSingleInstance(const QString &key)
{
return setSingleInstance(key, UserScope);
}
/*!
* \~chinese \brief DApplication::setSingleInstance 是一个重写函数,增加了控制单实例范围的 \a singleScope 参数。
* \~chinese 在Linux环境下默认使用DBus的方式实现单例判断,在其它环境或者设置了环境变量 DTK_USE_SEMAPHORE_SINGLEINSTANCE
* \~chinese 时使用系统信号量的方式实现单例判断
* \~chinese \param key 是确定程序唯一性的ID,一般使用程序的二进制名称即可。
* \~chinese \param singleScope 用于指定单实例的影响范围,具体见 \a DApplication::SingleScope。
* \~chinese \return 设置成功返回 true,否则返回 false。
*/
bool DApplication::setSingleInstance(const QString &key, SingleScope singleScope)
{
D_D(DApplication);
auto scope = singleScope == SystemScope ? DGuiApplicationHelper::WorldScope : DGuiApplicationHelper::UserScope;
connect(DGuiApplicationHelper::instance(), &DGuiApplicationHelper::newProcessInstance,
this, &DApplication::newInstanceStarted, Qt::UniqueConnection);
return DGuiApplicationHelper::setSingleInstance(key, scope);
}
/*!
* \~english \brief DApplication::loadTranslator loads translate file form
* \~english system or application data path;
* \~english \param localeFallback, a list of fallback locale you want load.
* \~english \return load success
*
* \~chinese \brief DApplication::loadTranslator 加载程序的翻译文件。
* \~chinese 使用这个函数需要保证翻译文件必须正确命名: 例如程序名叫 dde-dock,
* \~chinese 那么翻译文件在中文locale下的名称必须是 dde-dock_zh_CN.qm;翻译文件还需要放置
* \~chinese 在特定的位置,此函数会按照优先级顺序在以下目录中查找翻译文件:
* \~chinese 1. ~/.local/share/APPNAME/translations;
* \~chinese 2. /usr/local/share/APPNAME/translations;
* \~chinese 3. /usr/share/APPNAME/translations;
*
* \~chinese \param localeFallback 指定了回退的locale列表,默认只有系统locale。
* \~chinese \return 加载成功返回 true,否则返回 false。
*/
bool DApplication::loadTranslator(QList<QLocale> localeFallback)
{
D_D(DApplication);
d->loadDtkTranslator(localeFallback);
QList<DPathBuf> translateDirs;
auto appName = applicationName();
//("/home/user/.local/share", "/usr/local/share", "/usr/share")
auto dataDirs = DStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
for (const auto &path : dataDirs) {
DPathBuf DPathBuf(path);
translateDirs << DPathBuf / appName / "translations";
}
DPathBuf runDir(this->applicationDirPath());
translateDirs << runDir.join("translations");
DPathBuf currentDir(QDir::currentPath());
translateDirs << currentDir.join("translations");
#ifdef DTK_STATIC_TRANSLATION
translateDirs << DPathBuf(":/dtk/translations");
#endif
return d->loadTranslator(translateDirs, appName, localeFallback);
}
/*!
* \~chinese \brief DApplication::loadDXcbPlugin 强制程序使用的平台插件到dxcb。
* \~chinese 这个函数的工作原理是通过设置 QT_QPA_PLATFORM 来影响平台插件的加载,所以此函数
* \~chinese 必须在 DApplication 实例创建前进行调用。
* \~chinese \return 设置成功返回 true,否则返回 false。
*/
bool DApplication::loadDXcbPlugin()
{
Q_ASSERT_X(!qApp, "DApplication::loadDxcbPlugin", "Must call before QGuiApplication defined object");
if (!QPlatformIntegrationFactory::keys().contains(DXCB_PLUGIN_KEY)) {
return false;
}
// fix QGuiApplication::platformName() to xcb
qputenv("DXCB_FAKE_PLATFORM_NAME_XCB", "true");
return qputenv("QT_QPA_PLATFORM", DXCB_PLUGIN_KEY);
}
/*!
* \~chinese \brief DApplication::isDXcbPlatform 检查当前程序是否使用了dxcb平台插件。
* \~chinese \return 正在使用返回 true,否则返回 false。
*/
bool DApplication::isDXcbPlatform()
{
return DGUI_NAMESPACE::DPlatformHandle::isDXcbPlatform();
}
/*!
* \~chinese \brief DApplication::buildDtkVersion 返回编译时的dtk版本;
*/
int DApplication::buildDtkVersion()
{
return DtkBuildVersion::value;
}
/*!
* \~chinese \brief DApplication::runtimeDtkVersion 返回运行时的dtk版本;
*/
int DApplication::runtimeDtkVersion()
{
return DTK_VERSION;
}
/*!
* \~chinese \brief DApplication::registerDDESession 用于跟 startdde 进行通信,告知
* \~chinese startdde 进程已经启动成功。
* \~chinese \note 只有DDE系统组件需要使用此函数,普通应用无需使用。
*/
void DApplication::registerDDESession()
{
#ifdef Q_OS_LINUX
QString envName("DDE_SESSION_PROCESS_COOKIE_ID");
QByteArray cookie = qgetenv(envName.toUtf8().data());
qunsetenv(envName.toUtf8().data());
if (!cookie.isEmpty()) {
DDBusSender()
.service("com.deepin.SessionManager")
.path("/com/deepin/SessionManager")
.interface("com.deepin.SessionManager")
.method("Register")
.arg(QString(cookie))
.call();
}
#endif
}
/*!
* \~chinese \brief DApplication::customQtThemeConfigPathByUserHome
* \~chinese 根据用户家目录设置Qt主题配置文件的目录。
* \~chinese \param home 家目录,不要以 "/" 结尾
* \~chinese \warning 必须在构造 DApplication 对象之前调用
* \~chinese \sa DApplication::customQtThemeConfigPathByUserHome
*/
void DApplication::customQtThemeConfigPathByUserHome(const QString &home)
{
customQtThemeConfigPath(home + "/.config");
}
/*!
* \~chinese \brief DApplication::customQtThemeConfigPath
* \~chinese 自定义Qt主题配置文件的路径。
*
* \~chinese 默认文件通常为 "~/.config/deepin/qt-theme.ini"
* \~chinese 其中包含应用的图标主题、字体、、屏幕缩放等相关的配置项。可应用于以root用户启动的
* \~chinese 应用,需要跟随某个一般用户的主题设置项。
* \~chinese \a path 中不包含 "/deepin/qt-theme.ini" 部分,如:path = "/tmp",
* \~chinese 则配置文件路径为:"/tmp/deepin/qt-theme.ini"。
* \~chinese \param path 不要以 "/" 结尾
* \~chinese \warning 必须在构造 DApplication 对象之前调用
*/
void DApplication::customQtThemeConfigPath(const QString &path)
{
Q_ASSERT_X(!qApp, "DApplication::customQtThemeConfigPath", "Must call before QGuiApplication defined object");
qputenv(QT_THEME_CONFIG_PATH, path.toLocal8Bit());
}
/*!
* \~chinese \brief DApplication::customizedQtThemeConfigPath
* \~chinese \return 返回自定义的 Qt 主题配置文件路径,未设置过此路径时返回为空。
* \~chinese \sa DApplication::customQtThemeConfigPath
*/
QString DApplication::customizedQtThemeConfigPath()
{
return QString::fromLocal8Bit(qgetenv(QT_THEME_CONFIG_PATH));
}
/**
* \~english @brief DApplication::productName returns the product name of this application.
*
* \~english It's mainly used to construct an about dialog of the application.
*
* \~english @return the product name of this application if set, otherwise the applicationDisplayName.
*
*
* \~chinese \property DApplication::productName
* \~chinese \brief productName属性是程序的产品名称,
* \~chinese 产品名称不同与 applicationName ,应该是类似如“深度终端”,而不是 deepin-terminal,
* \~chinese 这个名称主要用于在程序的关于对话框中进行展示。
* \~chinese 如果没有手动通过 setProductName 来设置,会尝试使用 QApplication::applicationDisplayName 来充当产品名称。
*
* \sa productIcon, aboutDialog
*/
QString DApplication::productName() const
{
D_DC(DApplication);
return d->productName.isEmpty() ? applicationDisplayName() : d->productName;
}
/**
* \~english @brief DApplication::setProductName sets the product name of this application.
* \~english @param productName is the product name to be set.
*/
void DApplication::setProductName(const QString &productName)
{
D_D(DApplication);
d->productName = productName;
}
/**
* \~english @brief DApplication::productIcon returns the product icon of this application.
*
* \~english It's mainly used to construct an about dialog of the application.
*
* \~english @return the product icon of this application if set, otherwise empty.
*
*
* \~chinese \property DApplication::productIcon
* \~chinese \brief productIcon 属性是程序的产品图标,
* \~chinese 主要用于在关于对话框中进行展示。
*
* \sa productName, aboutDialog
*/
const QIcon &DApplication::productIcon() const
{
D_DC(DApplication);
return d->productIcon;
}
/**
* \~english @brief DApplication::setProductIcon sets the product icon of this application.
* \~english @param productIcon is the product icon to be set.
*/
void DApplication::setProductIcon(const QIcon &productIcon)
{
D_D(DApplication);
d->productIcon = productIcon;
}
/**
* \~english @brief DApplication::applicationLicense returns the license used by this application.
*
* \~english It's mainly used to construct an about dialog of the application.
*
* \~english @return the license used by this application.
*
*
* \~chinese \property DApplication::applicationLicense
* \~chinese \brief applicationLicense 属性是程序所使用的授权协议;
* \~chinese 主要用于在关于对话框中进行展示,默认值为 GPLv3。
*/
QString DApplication::applicationLicense() const
{
D_DC(DApplication);
return d->appLicense;
}
/**
* \~english @brief DApplication::setApplicationLicense sets the license of this application.
* \~english @param license is the license to be set.
*/
void DApplication::setApplicationLicense(const QString &license)
{
D_D(DApplication);
d->appLicense = license;
}
/**
* \~english @brief DApplication::applicationDescription returns the long description of the application.
*
* \~english It's mainly used to construct an about dialog of the application.
*
* \~english @return the description of the application if set, otherwise empty.
*
*
* \~chinese \property DApplication::applicationDescription
* \~chinese \brief applicationDescription 属性记录了程序的描述信息,主要用于关于对话框中的信息展示。
*/
QString DApplication::applicationDescription() const
{
D_DC(DApplication);
return d->appDescription;
}
/**
* \~english @brief DApplication::setApplicationDescription sets the description of the application.
* \~english @param description is description to be set.
*/
void DApplication::setApplicationDescription(const QString &description)
{
D_D(DApplication);
d->appDescription = description;
}
/*!
* \~chinese \property DApplication::applicationHomePage
* \~chinese \brief applicationHomePage 属性记录程序的主页网址,主要用于在关于对话框中进行展示。
*/
QString DApplication::applicationHomePage() const
{
D_DC(DApplication);
return d->homePage;
}
void DApplication::setApplicationHomePage(const QString &link)
{
D_D(DApplication);
d->homePage = link;
}
/**
* \~english @brief DApplication::applicationAcknowledgementPage returns the acknowlegement page of the application.
*
* \~english It's mainly used to construct an about dialog of the application.
* \~english @return the acknowlegement page of the application if set, otherwise empty.
*
*
* \~chinese \property DApplication::applicationAcknowledgementPage
* \~chinese \brief applicationAcknowledgementPage 属性记录程序的鸣谢信息网址,主要用于在关于对话框中进行展示。
*/
QString DApplication::applicationAcknowledgementPage() const
{
D_DC(DApplication);
return d->acknowledgementPage;
}
/**
* \~english @brief DApplication::setApplicationAcknowledgementPage sets the acknowlegement page of the application.
* \~english @param link is the acknowlegement page link to be shown in the about dialog.
*/
void DApplication::setApplicationAcknowledgementPage(const QString &link)
{
D_D(DApplication);
d->acknowledgementPage = link;
}
/*!
* \~chinese \property DApplication::applicationAcknowledgementVisible
* \~chinese \brief applicationAcknowledgementVisible 属性控制是否显示关于对话框中的鸣谢地址显示。
*/
bool DApplication::applicationAcknowledgementVisible() const
{
D_DC(DApplication);
return d->acknowledgementPageVisible;
}
void DApplication::setApplicationAcknowledgementVisible(bool visible)
{
D_D(DApplication);
d->acknowledgementPageVisible = visible;
}
/**
* \~english @brief DApplication::aboutDialog returns the about dialog of this application.
*
* \~english If the about dialog is not set, it will automatically construct one.
*
* \~english @return the about dialog instance.
*
*
* \~chinese \brief DApplication::aboutDialog 返回一个基于当前程序信息的关于对话框。
* \~chinese 此对话框可以通过 DApplication::setAboutDialog 进行设置,如果没有设置就使用此函数进行获取,
* \~chinese 系统会创建一个新的关于对话框。
*
* \sa setAboutDialog
*/
DAboutDialog *DApplication::aboutDialog()
{
D_D(DApplication);
return d->aboutDialog;
}
/**
* \~english @brief DApplication::setAboutDialog sets the about dialog of this application.
*
* \~english It's mainly used to override the auto-constructed about dialog which is not
* \~english a common case, so please do double check before using this method.
*
* \~english @param aboutDialog
*
*
* \~chinese \brief DApplication::setAboutDialog 为当前程序设置一个关于对话框。
*
* \sa aboutDialog
*/
void DApplication::setAboutDialog(DAboutDialog *aboutDialog)
{
D_D(DApplication);
if (d->aboutDialog && d->aboutDialog != aboutDialog) {
d->aboutDialog->deleteLater();
}
d->aboutDialog = aboutDialog;
}
/*!
* \~chinese \property DApplication::visibleMenuShortcutText
* \~chinese \brief visibleMenuShortcutText 属性代表了程序中菜单项是否显示对应的快捷键。
*/
bool DApplication::visibleMenuShortcutText() const
{
D_DC(DApplication);
return d->visibleMenuShortcutText;
}
void DApplication::setVisibleMenuShortcutText(bool value)
{
D_D(DApplication);
d->visibleMenuShortcutText = value;
}
/*!
* \~chinese \property DApplication::visibleMenuCheckboxWidget
* \~chinese \brief visibleMenuCheckboxWidget 属性代表了程序中菜单项是否显示Checkbox控件。
*/
bool DApplication::visibleMenuCheckboxWidget() const
{
D_DC(DApplication);
return d->visibleMenuCheckboxWidget;
}
void DApplication::setVisibleMenuCheckboxWidget(bool value)
{
D_D(DApplication);
d->visibleMenuCheckboxWidget = value;
}