1
1
#include " main.hpp"
2
2
#include < algorithm>
3
+ #include < array>
4
+ #include < cerrno>
3
5
#include < cstdio>
4
6
#include < cstdlib>
5
7
#include < limits>
8
10
#include < CLI/App.hpp>
9
11
#include < CLI/CLI.hpp> // NOLINT: Need to include this for impls of some CLI11 classes
10
12
#include < CLI/Validators.hpp>
13
+ #include < fcntl.h>
11
14
#include < qapplication.h>
12
15
#include < qcontainerfwd.h>
13
16
#include < qcoreapplication.h>
@@ -55,6 +58,34 @@ using qs::ipc::IpcClient;
55
58
void checkCrashRelaunch (char ** argv, QCoreApplication* coreApplication);
56
59
int runCommand (int argc, char ** argv, QCoreApplication* coreApplication);
57
60
61
+ int DAEMON_PIPE = -1 ; // NOLINT
62
+ void exitDaemon (int code) {
63
+ if (DAEMON_PIPE == -1 ) return ;
64
+
65
+ if (write (DAEMON_PIPE, &code, sizeof (int )) == -1 ) {
66
+ qCritical ().nospace () << " Failed to write daemon exit command with error code " << errno << " : "
67
+ << qt_error_string ();
68
+ }
69
+
70
+ close (DAEMON_PIPE);
71
+
72
+ close (STDIN_FILENO);
73
+ close (STDOUT_FILENO);
74
+ close (STDERR_FILENO);
75
+
76
+ if (open (" /dev/null" , O_RDONLY) != STDIN_FILENO) { // NOLINT
77
+ qFatal () << " Failed to open /dev/null on stdin" ;
78
+ }
79
+
80
+ if (open (" /dev/null" , O_WRONLY) != STDOUT_FILENO) { // NOLINT
81
+ qFatal () << " Failed to open /dev/null on stdout" ;
82
+ }
83
+
84
+ if (open (" /dev/null" , O_WRONLY) != STDERR_FILENO) { // NOLINT
85
+ qFatal () << " Failed to open /dev/null on stderr" ;
86
+ }
87
+ }
88
+
58
89
int main (int argc, char ** argv) {
59
90
QCoreApplication::setApplicationName (" quickshell" );
60
91
@@ -66,7 +97,10 @@ int main(int argc, char** argv) {
66
97
auto * coreApplication = new QCoreApplication (qArgC, argv);
67
98
68
99
checkCrashRelaunch (argv, coreApplication);
69
- return runCommand (argc, argv, coreApplication);
100
+ auto code = runCommand (argc, argv, coreApplication);
101
+
102
+ exitDaemon (code);
103
+ return code;
70
104
}
71
105
72
106
class QStringOption {
@@ -133,6 +167,7 @@ struct CommandState {
133
167
bool printVersion = false ;
134
168
bool killAll = false ;
135
169
bool noDuplicate = false ;
170
+ bool daemonize = false ;
136
171
} misc;
137
172
};
138
173
@@ -241,8 +276,11 @@ int runCommand(int argc, char** argv, QCoreApplication* coreApplication) {
241
276
cli.add_flag (" -V,--version" , state.misc .printVersion )
242
277
->description (" Print quickshell's version and exit." );
243
278
244
- cli.add_flag (" --no-duplicate" , state.misc .noDuplicate )
279
+ cli.add_flag (" -n,- -no-duplicate" , state.misc .noDuplicate )
245
280
->description (" Exit immediately if another instance of the given config is running." );
281
+
282
+ cli.add_flag (" -d,--daemonize" , state.misc .daemonize )
283
+ ->description (" Detach from the controlling terminal." );
246
284
}
247
285
248
286
{
@@ -295,6 +333,40 @@ int runCommand(int argc, char** argv, QCoreApplication* coreApplication) {
295
333
296
334
CLI11_PARSE (cli, argc, argv);
297
335
336
+ // Has to happen before extra threads are spawned.
337
+ if (state.misc .daemonize ) {
338
+ auto closepipes = std::array<int , 2 >();
339
+ if (pipe (closepipes.data ()) == -1 ) {
340
+ qFatal ().nospace () << " Failed to create messaging pipes for daemon with error " << errno
341
+ << " : " << qt_error_string ();
342
+ }
343
+
344
+ DAEMON_PIPE = closepipes[1 ];
345
+
346
+ pid_t pid = fork (); // NOLINT (include)
347
+
348
+ if (pid == -1 ) {
349
+ qFatal ().nospace () << " Failed to fork daemon with error " << errno << " : "
350
+ << qt_error_string ();
351
+ } else if (pid == 0 ) {
352
+ close (closepipes[0 ]);
353
+
354
+ if (setsid () == -1 ) {
355
+ qFatal ().nospace () << " Failed to setsid with error " << errno << " : " << qt_error_string ();
356
+ }
357
+ } else {
358
+ close (closepipes[1 ]);
359
+ qInfo () << " Daemon launched." ;
360
+
361
+ int ret = 0 ;
362
+ if (read (closepipes[0 ], &ret, sizeof (int )) == -1 ) {
363
+ qFatal () << " Failed to wait for daemon launch (it may have crashed)" ;
364
+ }
365
+
366
+ return ret;
367
+ }
368
+ }
369
+
298
370
{
299
371
auto level = state.log .verbosity == 0 ? QtWarningMsg
300
372
: state.log .verbosity == 1 ? QtInfoMsg
@@ -489,7 +561,7 @@ int readLogFile(CommandState& cmd) {
489
561
490
562
int listInstances (CommandState& cmd) {
491
563
auto * basePath = QsPaths::instance ()->baseRunDir ();
492
- if (!basePath) exit (- 1 ) ; // NOLINT
564
+ if (!basePath) return - 1 ; // NOLINT
493
565
494
566
QString path;
495
567
QString configFilePath;
@@ -648,7 +720,7 @@ int launchFromCommand(CommandState& cmd, QCoreApplication* coreApplication) {
648
720
{
649
721
InstanceLockInfo info;
650
722
if (cmd.misc .noDuplicate && selectInstance (cmd, &info) == 0 ) {
651
- qCDebug (logBare) << " An instance of this configuration is already running." ;
723
+ qCInfo (logBare) << " An instance of this configuration is already running." ;
652
724
return 0 ;
653
725
}
654
726
}
@@ -834,6 +906,8 @@ int launch(const LaunchArgs& args, char** argv, QCoreApplication* coreApplicatio
834
906
auto root = RootWrapper (args.configPath , shellId);
835
907
QGuiApplication::setQuitOnLastWindowClosed (false );
836
908
909
+ exitDaemon (0 );
910
+
837
911
auto code = QGuiApplication::exec ();
838
912
delete app;
839
913
return code;
0 commit comments