Settings: unify duplicated code
[lxde/liblxqt.git] / lxqtapplication.cpp
1 /* BEGIN_COMMON_COPYRIGHT_HEADER
2 * (c)LGPL2+
3 *
4 * LXQt - a lightweight, Qt based, desktop toolset
5 * http://razor-qt.org
6 *
7 * Copyright: 2012-2013 Razor team
8 * Authors:
9 * Petr Vanek <petr@scribus.info>
10 *
11 * This program or library is free software; you can redistribute it
12 * and/or modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
15 *
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
20
21 * You should have received a copy of the GNU Lesser General
22 * Public License along with this library; if not, write to the
23 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24 * Boston, MA 02110-1301 USA
25 *
26 * END_COMMON_COPYRIGHT_HEADER */
27
28 #include <QDir>
29
30 #include "lxqtapplication.h"
31 #include "lxqtsettings.h"
32
33 #include <XdgDirs>
34
35 using namespace LXQt;
36
37 #define COLOR_DEBUG "\033[32;2m"
38 #define COLOR_WARN "\033[33;2m"
39 #define COLOR_CRITICAL "\033[31;1m"
40 #define COLOR_FATAL "\033[33;1m"
41 #define COLOR_RESET "\033[0m"
42
43 #define QAPP_NAME qApp ? qApp->objectName().toUtf8().constData() : ""
44
45 #include <cstdio>
46 #include <unistd.h>
47 #include <cstring>
48 #include <csignal>
49 #include <sys/socket.h>
50 #include <QDateTime>
51 #include <QDebug>
52 #include <QSocketNotifier>
53 /*! \brief Log qDebug input to file
54 Used only in pure Debug builds or when is the system environment
55 variable LXQT_DEBUG set
56 */
57 void dbgMessageOutput(QtMsgType type, const QMessageLogContext &ctx, const QString & msgStr)
58 {
59 QByteArray msgBuf = msgStr.toUtf8();
60 const char* msg = msgBuf.constData();
61 QDir dir(XdgDirs::configHome().toUtf8() + QLatin1String("/lxqt"));
62 dir.mkpath(".");
63
64 const char* typestr;
65 const char* color;
66 switch (type) {
67 case QtDebugMsg:
68 typestr = "Debug";
69 color = COLOR_DEBUG;
70 break;
71 case QtWarningMsg:
72 typestr = "Warning";
73 color = COLOR_WARN;
74 break;
75 case QtFatalMsg:
76 typestr = "Fatal";
77 color = COLOR_FATAL;
78 break;
79 default: // QtCriticalMsg
80 typestr = "Critical";
81 color = COLOR_CRITICAL;
82 }
83
84 QByteArray dt = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz").toUtf8();
85 if (isatty(STDERR_FILENO))
86 fprintf(stderr, "%s %s(%p) %s: %s%s\n", color, QAPP_NAME, qApp, typestr, msg, COLOR_RESET);
87 else
88 fprintf(stderr, "%s(%p) %s: %s\n", QAPP_NAME, qApp, typestr, msg);
89
90 FILE *f = fopen(dir.absoluteFilePath("debug.log").toUtf8().constData(), "a+");
91 fprintf(f, "%s %s(%p) %s: %s\n", dt.constData(), QAPP_NAME, qApp, typestr, msg);
92 fclose(f);
93
94 if (type == QtFatalMsg)
95 abort();
96 }
97
98 Application::Application(int &argc, char** argv)
99 : QApplication(argc, argv)
100 {
101 #ifdef DEBUG
102 qInstallMessageHandler(dbgMessageOutput);
103 #else
104 if (!qgetenv("LXQT_DEBUG").isNull())
105 qInstallMessageHandler(dbgMessageOutput);
106 #endif
107
108 setWindowIcon(QIcon(QString(LXQT_GRAPHICS_DIR) + "/lxqt_logo.png"));
109 connect(Settings::globalSettings(), SIGNAL(lxqtThemeChanged()), this, SLOT(updateTheme()));
110 updateTheme();
111 }
112
113 Application::Application(int &argc, char** argv, bool handleQuitSignals)
114 : Application(argc, argv)
115 {
116 if (handleQuitSignals)
117 {
118 QList<int> signo_list = {SIGINT, SIGTERM, SIGHUP};
119 connect(this, &Application::unixSignal, [this, signo_list] (int signo)
120 {
121 if (signo_list.contains(signo))
122 quit();
123 });
124 listenToUnixSignals(signo_list);
125 }
126 }
127
128 void Application::updateTheme()
129 {
130 QString styleSheetKey = QFileInfo(applicationFilePath()).fileName();
131 setStyleSheet(lxqtTheme.qss(styleSheetKey));
132 emit themeChanged();
133 }
134
135 namespace
136 {
137 class SignalHandler
138 {
139 public:
140 static void signalHandler(int signo)
141 {
142 int ret = write(instance->mSignalSock[0], &signo, sizeof (int));
143 if (sizeof (int) != ret)
144 qCritical() << QStringLiteral("unable to write into socketpair, %1").arg(strerror(errno));
145 }
146
147 public:
148 template <class Lambda>
149 SignalHandler(Lambda signalEmitter)
150 : mSignalSock{-1, -1}
151 {
152 if (0 != socketpair(AF_UNIX, SOCK_STREAM, 0, mSignalSock))
153 {
154 qCritical() << QStringLiteral("unable to create socketpair for correct signal handling: %1)").arg(strerror(errno));
155 return;
156 }
157
158 mNotifier.reset(new QSocketNotifier(mSignalSock[1], QSocketNotifier::Read));
159 QObject::connect(mNotifier.data(), &QSocketNotifier::activated, [this, signalEmitter] {
160 int signo = 0;
161 int ret = read(mSignalSock[1], &signo, sizeof (int));
162 if (sizeof (int) != ret)
163 qCritical() << QStringLiteral("unable to read signal from socketpair, %1").arg(strerror(errno));
164 signalEmitter(signo);
165 });
166 }
167
168 ~SignalHandler()
169 {
170 close(mSignalSock[0]);
171 close(mSignalSock[1]);
172 }
173
174 void listenToSignals(QList<int> const & signoList)
175 {
176 struct sigaction sa;
177 sa.sa_handler = signalHandler;
178 sigemptyset(&sa.sa_mask);
179 sa.sa_flags = 0;
180 for (auto const & signo : signoList)
181 sigaction(signo, &sa, nullptr);
182 }
183
184 public:
185 static QScopedPointer<SignalHandler> instance;
186
187 private:
188 int mSignalSock[2];
189 QScopedPointer<QSocketNotifier> mNotifier;
190 };
191
192 QScopedPointer<SignalHandler> SignalHandler::instance;
193 }
194
195 void Application::listenToUnixSignals(QList<int> const & signoList)
196 {
197 static QScopedPointer<QSocketNotifier> signal_notifier;
198
199 if (SignalHandler::instance.isNull())
200 SignalHandler::instance.reset(new SignalHandler{[this] (int signo) { emit unixSignal(signo); }});
201 SignalHandler::instance->listenToSignals(signoList);
202 }