6

My program can run on a server with no GUI, or on a desktop. When it runs on a system that can display GUIs I want to instantiate QApplication, and when it is on a server I want QCoreApplication.

If I instanciate QApplication on a server, it either Segfault (at least it used to), or display an error message and exit, without letting me the chance to instantiate QCoreApplication instead:

This application failed to start because it could not find or load the Qt platform plugin "xcb". Available platform plugins are: linuxfb, minimal, offscreen. Reinstalling the application may fix this problem.

Seriously ?

Currently I just pass a -noGui argument when I run my program on a server. It works fine, but I want to detect if the system can use QApplication or not, so I can get rid of this argument.

I am sure there is already an answer to that somewhere, but I can't get a hand on it.

deck
  • 343
  • 2
  • 11
  • Why don't you just check against the plugins then? – László Papp Nov 03 '14 at 04:10
  • Plugins can vary across systems, which could lead to false positives. I work with Qt for the "code once, works everywhere" thingy. I'd prefer a cleaner and standard way in the Qt library, but yes, that could be a last resort solution. – deck Nov 03 '14 at 04:20
  • Not really, no, in fact, this could be programmed without ifdefs. – László Papp Nov 03 '14 at 04:21
  • Yes but if I understood correctly, you suggest to check if one or several plugins are only present when QApplication can be used, which doesn't sound very reliable. I will try it tomorrow anyway, thanks. Still searching for a cleaner solution. – deck Nov 03 '14 at 04:27
  • I am not sure if Qt book keeps these plugins internally, but I would assume no, and it would also be error-prone on their side. Why don't you just make sure by using an explicit option? – László Papp Nov 03 '14 at 04:40
  • I already have an explicit option which tell if QApplication or QCoreApplication have to be used, but it puts the burden on the user to use it correctly, and if he fails, the program just wont start. It is not a choice that the user can make. The program have to do it by itself. My users are supposed to be everyone, and I can't bother them with something like that. – deck Nov 03 '14 at 04:49
  • Could you create a `bash` script that tries to run your application as a GUI. If it exits with an error return value then you launch it with the `-noGui` option? – Michael Petch Nov 03 '14 at 05:02
  • I can't set an exit error value since I am not the one quitting the program. But yes, this could still be a solution, but I hope there exists a cleaner way to do it. I mean I just don't want a class I instantiate to blow up my program, that sounds crazy... – deck Nov 03 '14 at 05:26
  • I can also launch a small program from my main program, see if it crashes when calling QApplication, and call QCoreApplication if it does. But that's dirty. – deck Nov 03 '14 at 05:44
  • 1
    Yeah, right... and what if I _want_ to run cli even when the gui is available? This automagically think instead of the user sounds bad to me. – László Papp Nov 03 '14 at 07:14
  • 1
    Why would an inexperienced user (i.e. one incapable of setting a command line option) be operating a headless server!? The standard solution to this is to provide a command line argument. – cmannett85 Nov 03 '14 at 08:48
  • If the user doesn't want a gui on a gui capable system he can still use the -noGui option, this is his choice. But on a server there is no choice to make, and the program should be smart enough to run, and not crash for a non user dependent reason. – deck Nov 03 '14 at 13:52

1 Answers1

5

Just in case anyone ever wonder how I solved this issue, I intercept the SIGABRT signal sent by QApplication, and instantiate QCoreApplication instead. It works surprisingly well, and it is cross-platform.

#include <QApplication>
#include <csetjmp>
#include <csignal>
#include <cstdlib>

jmp_buf env;

void onSigabrt(int)
{
    longjmp (env, 1);
}

QCoreApplication *loadQt(bool gui)
{
    QCoreApplication *application = NULL;

    if (gui)
    {
        if (setjmp(env) == 0)
        {
            signal(SIGABRT, &onSigabrt);
            application = new QApplication();
        }
        signal(SIGABRT, SIG_DFL);
    }
    if (!application)
        application = new QCoreApplication();
    return (application);
}
deck
  • 343
  • 2
  • 11