Code Monkey home page Code Monkey logo

singleapplication's Introduction

SingleApplication

CI

This is a replacement of the QtSingleApplication for Qt5 and Qt6.

Keeps the Primary Instance of your Application and kills each subsequent instances. It can (if enabled) spawn secondary (non-related to the primary) instances and can send data to the primary instance from secondary instances.

You can find the full usage reference and examples here.

Usage

The SingleApplication class inherits from whatever Q[Core|Gui]Application class you specify via the QAPPLICATION_CLASS macro (QCoreApplication is the default). Further usage is similar to the use of the Q[Core|Gui]Application classes.

You can use the library as if you use any other QCoreApplication derived class:

#include <QApplication>
#include <SingleApplication.h>

int main( int argc, char* argv[] )
{
    SingleApplication app( argc, argv );

    return app.exec();
}

To include the library files I would recommend that you add it as a git submodule to your project. Here is how:

git submodule add https://github.com/itay-grudev/SingleApplication.git singleapplication

Qmake:

Then include the singleapplication.pri file in your .pro project file.

include(singleapplication/singleapplication.pri)
DEFINES += QAPPLICATION_CLASS=QApplication

CMake:

Then include the subdirectory in your CMakeLists.txt project file.

set(QAPPLICATION_CLASS QApplication CACHE STRING "Inheritance class for SingleApplication")
add_subdirectory(src/third-party/singleapplication)
target_link_libraries(${PROJECT_NAME} SingleApplication::SingleApplication)

Directly including this repository as a Git submodule, or even just a shallow copy of the source code into new projects might not be ideal when using CMake. Another option is using CMake's FetchContent module, available since version 3.11.

# Define the minumun CMake version, as an example 3.24
cmake_minimum_required(VERSION 3.24)

# Include the module
include(FetchContent)

# If using Qt6, override DEFAULT_MAJOR_VERSION
set(QT_DEFAULT_MAJOR_VERSION 6 CACHE STRING "Qt version to use, defaults to 6")

# Set QAPPLICATION_CLASS
set(QAPPLICATION_CLASS QApplication CACHE STRING "Inheritance class for SingleApplication")


# Declare how is the source going to be obtained
FetchContent_Declare(
  SingleApplication
  GIT_REPOSITORY https://github.com/itay-grudev/SingleApplication
  GIT_TAG        master
  #GIT_TAG        e22a6bc235281152b0041ce39d4827b961b66ea6
)

# Fetch the repository and make it available to the build
FetchContent_MakeAvailable(SingleApplication)

# Then simply use find_package as usual
find_package(SingleApplication)

# Finally add it to the target_link_libraries() section
target_link_libraries(ClientePOS PRIVATE
    Qt${QT_VERSION_MAJOR}::Widgets
    Qt${QT_VERSION_MAJOR}::Network
    Qt${QT_VERSION_MAJOR}::Sql

    SingleApplication::SingleApplication
)

The library sets up a QLocalServer and a QSharedMemory block. The first instance of your Application is your Primary Instance. It would check if the shared memory block exists and if not it will start a QLocalServer and listen for connections. Each subsequent instance of your application would check if the shared memory block exists and if it does, it will connect to the QLocalServer to notify the primary instance that a new instance had been started, after which it would terminate with status code 0. In the Primary Instance SingleApplication would emit the instanceStarted() signal upon detecting that a new instance had been started.

The library uses stdlib to terminate the program with the exit() function.

Also don't forget to specify which QCoreApplication class your app is using if it is not QCoreApplication as in examples above.

Instance started signal

The SingleApplication class implements a instanceStarted() signal. You can bind to that signal to raise your application's window when a new instance had been started, for example.

// window is a QWindow instance
QObject::connect(
    &app,
    &SingleApplication::instanceStarted,
    &window,
    &QWindow::raise
);

Using SingleApplication::instance() is a neat way to get the SingleApplication instance for binding to it's signals anywhere in your program.

Note: On Windows the ability to bring the application windows to the foreground is restricted. See Windows specific implementations for a workaround and an example implementation.

Secondary Instances

If you want to be able to launch additional Secondary Instances (not related to your Primary Instance) you have to enable that with the third parameter of the SingleApplication constructor. The default is false meaning no Secondary Instances. Here is an example of how you would start a Secondary Instance send a message with the command line arguments to the primary instance and then shut down.

int main(int argc, char *argv[])
{
    SingleApplication app( argc, argv, true );

    if( app.isSecondary() ) {
        app.sendMessage(  app.arguments().join(' ')).toUtf8() );
        app.exit( 0 );
    }

    return app.exec();
}

Note: A secondary instance won't cause the emission of the instanceStarted() signal by default. See SingleApplication::Mode for more details.*

You can check whether your instance is a primary or secondary with the following methods:

app.isPrimary();
// or
app.isSecondary();

Note: If your Primary Instance is terminated a newly launched instance will replace the Primary one even if the Secondary flag has been set.*

Examples

There are three examples provided in this repository:

Versioning

Each major version introduces either very significant changes or is not backwards compatible with the previous version. Minor versions only add additional features, bug fixes or performance improvements and are backwards compatible with the previous release. See CHANGELOG.md for more details.

Implementation

The library is implemented with a QSharedMemory block which is thread safe and guarantees a race condition will not occur. It also uses a QLocalSocket to notify the main process that a new instance had been spawned and thus invoke the instanceStarted() signal and for messaging the primary instance.

Additionally the library can recover from being forcefully killed on *nix systems and will reset the memory block given that there are no other instances running.

License

This library and it's supporting documentation, with the exception of the Qt calculator examples which is distributed under the BSD license, are released under the terms of The MIT License (MIT) with an extra condition, that:

Permission is not granted to use this software or any of the associated files
as sample data for the purposes of building machine learning models.

singleapplication's People

Contributors

autoantwort avatar bg4444 avatar carlos22 avatar christoph-cullmann avatar dail8859 avatar deepbluev7 avatar defaultsamson avatar dschulz avatar emericg avatar giraldeau avatar iakov avatar itay-grudev avatar jbuckmccready avatar jonaski avatar kolcha avatar liulex avatar lorendb avatar mklein-de avatar moodyhunter avatar pbek avatar pjwhams avatar retmas avatar samsonwang avatar shatur avatar szinedine avatar triplef avatar uralbash avatar vitozz avatar wadealer avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

singleapplication's Issues

Build Error on Windows

I see this error on windows builds:

singleapplication\singleapplication_p.cpp:104: error: use of undeclared identifier 'timeout'

It looks like it was removed from the API at some point, removing the Q_UNUSED lets it pass.

Test auto cleanup on Linux

Test the automatic shared memory cleanup after crash (with uncatchable signals like SIGKILL) on Linux. There is little if nothing to be improved about this but would be nice to know the behavior of the library under extreme conditions on all platforms

Examples don't compile out-of-the-box with Qt 5.9.1

rts1-12:/opt/Qt/QtSingleApplication/examples/basic> qmake Info: creating stash file /opt/Qt/QtSingleApplication/examples/basic/.qmake.stash rts1-12:/opt/Qt/QtSingleApplication/examples/basic> ls basic.pro main.cpp Makefile rts1-12:/opt/Qt/QtSingleApplication/examples/basic> make g++ -c -pipe -O2 -std=gnu++11 -Wall -W -D_REENTRANT -fPIC -DQAPPLICATION_CLASS=QCoreApplication -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_NETWORK_LIB -DQT_CORE_LIB -I. -I../../../QtSingleApplication -I../../../5.9.1/gcc_64/include -I../../../5.9.1/gcc_64/include/QtGui -I../../../5.9.1/gcc_64/include/QtNetwork -I../../../5.9.1/gcc_64/include/QtCore -I. -isystem /usr/include/libdrm -I../../../5.9.1/gcc_64/mkspecs/linux-g++ -o singleapplication.o ../../singleapplication.cpp ../../singleapplication.cpp: In static member function โ€˜static void SingleApplicationPrivate::terminate(int)โ€™: ../../singleapplication.cpp:243:37: error: โ€˜QApplicationโ€™ has not been declared delete ((SingleApplication*)QApplication::instance())->d_ptr; ^ make: *** [singleapplication.o] Error 1

QGuiApplication not work

I'm trying to use singleapp with QGuiApplication as base class.

#ifndef QAPPLICATION_CLASS
  #define QAPPLICATION_CLASS QGuiApplication
#endif

#include "singleapplication.h"

int main(int argc, char *argv[])
{
    // QGuiApplication app(argc, argv);  --> Work
    SingleApplication app(argc, argv);

but everytime get error:

Cannot create window: no screens available

feature? add option for create different SingleApplication with different id.

Hi, Itay.

I found that SingleApplication has a limitation of creating different "primary" app Instances.

The situation I met is that I have to create two progresses and they are both primary, but not same at all (each one can be see as a normal SingleApplication and can get message from secondary one).

My solution is add an optional argument for generating socket channel by this argument. see here

This project is very helpful for my works. I'm not sure it is a good idea for your project. I just used it and list which I've thought.

Cheers.

Requires Advapi32.lib on Windows

With Qt 5.7.1 32 bit MSVC 2015

singleapplication.obj : error LNK2019: unresolved external symbol __imp__GetUserNameW@8 referenced in function "public: void __thiscall SingleApplicationPri

Fixed by adding to the .pro (or .pri) file.

LIBS += Advapi32.lib

I don't know if Advapi32.lib is in the default libraries list, but I guess it is better to be safe by explicitly specifying it in the libraries list.

Signal Custom handling

Hi

It could be great if we can override/intercept the signals (SIGHUP , SIGINT, etc...). As our application could clean its resources and then next call a SingleApplication crash handler. Ex :

#include <QApplication>
#include <SingleApplication.h>

void myApplicationCrashHandler(int sig) {

    // Doing custom Qt Application clean-up....
    // ...
    // ...

    // Calling the SingleApplication normal crash handler
    SingleApplication::signalCrash(sig);
}

int main( int argc, char* argv[] )
{
    SingleApplication app( argc, argv );

    // Install a custom crash handler
    SingleApplication::installCrashHandler( &myApplicationCrashHandler );

    return app.exec();
}

Maybe this is already possible, but I have not found how. Because without the mechanism we cannot kill/free resources properly of our application.

Multithreading race. It is not a solution.

Run 2 or more processes.

They pseudo-paralell execute code

"socket->waitForConnected(1000)"

then they all go to the branch else
{
// If the connection is insuccessful, this is the main process
// So we create a Local Server
server = new QLocalServer();
server->removeServer(serverName);
server->listen(serverName);
QObject::connect(server, SIGNAL(newConnection()), this, SLOT(slotConnectionEstablished()));
}

and now we have 2 or more running processes;

Crash on android

Hi!
I'm using SingleApplication in one of my application and it's working great. I recently tried running that application on Android and iOS. It was seamless... except I had to manually disabled SingleApplication with ifdefs in order for the application to start.

Feature wise, SingleApplication doesn't really make sense in mobile apps anyway, but it would be super nice if it could (transparently) behave as a regular qapplication instead of crashing the app!

The only debug output that I have says:
W WatchFlower: (null):0 ((null)): Unimplemented code.
So I get that this is not very helpful, sorry, but I'm available if you need more infos or tests.

SingleApplication::instanceStarted signal won't trigger in random order

Hi and Thanks for the source code sharing.
I used this source as a submodule in my Qt/Quick application to block the second instance of the application and raise the previously hided ApplicationWindow(qml class).
so naturally replaced the QApplication with QGuiApplication in qmake:
include(singleapplication/singleapplication.pri)
DEFINES += QAPPLICATION_CLASS=QGuiApplication
and created a signal in one of my QML registered classes.
SingleApplication app( argc, argv, false, SingleApplication::Mode::User,100);
...
ControlCenter controlCenterObject;
QObject::connect( &app, &SingleApplication::instanceStarted, &controlCenterObject, &ControlCenter::raisWindow );
and if your familiar with the QML, created a Connection to receive the signal:
Connections{ target: ControlCenter onRaisWindow:{ console.log("Requested to raise the window") window.show() window.raise() window.requestActivate() } }
almost everything works fine but small problem is that it's not working every time i start a secondry instance of application.
I tracked down the issue and found out that the signal won't trigger from the SingleApplication.
Any idea what's wrong?

exited with code 134

Hi, I'm trying to integrate your code in my application.

I inserted in .pro file:

DEFINES += QT_DEPRECATED_WARNINGS QAPPLICATION_CLASS=QGuiApplication
include(singleapplication/singleapplication.pri)

and my main.cpp looks like:

#include "mainwindow.h"
#include <QApplication>
#include <singleapplication.h>

int main(int argc, char *argv[])
{
    SingleApplication app(argc, argv);

    MainWindow w;

    QObject::connect( &app, &SingleApplication::instanceStarted, [ &w ]() {
            w.raise();
            w.activateWindow();
    });

    w.show();

    return app.exec();
}

But the application FC at launch with the above error and debugger pointing to mainwindow.cpp:

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow) // <----- GDB stops here
{
    ui->setupUi(this);
    ....

Do you have any idea about the issue? Thanks for your time.

Add a function which returns the number of running instances

Feature request: Add a function which returns the number of running instances. (In fact, I only want to know if one instance is the only running instance.)

This is helpful if you want to behave differently on different number of instances.

My actual need is described in cpeditor/cpeditor#131, if you are interested in where this feature is useful.

Secondary instance wont become primary on primary exit

If a second instance is running and the primary instance exists, then a third instance started it cannot find the primary instance. The strange thing is that once in this state all of the next instances are seen as secondary until all instances exit.

NOTE: I am seeing this on Windows 10 1803

Better UserName

Hi,
Thanks for sharing the code,
you used QStandardPaths::standardLocations( QStandardPaths::HomeLocation ) for getting user info but Qt will use HOMEPATH environment variable on Windows that is not very reliable because it can be changed by user.
A better way is to use Win Api GetUserName or GetUserNameEx.

GL,
Hojjat.

How can I restart my application when I use SingleApplication

QTimer::singleShot(0, this, &CApplication::quit);
   
QProcess::startDetached(qApp->applicationFilePath(), {}, qApp->applicationDirPath());

I added this to my app.

and this is how I SingleApplication(argc, argv, true, ExcludeAppPath) construct it.

I just couldn't make it restart.

But it works with QApplication.

Would you please help

Compiling in MSVC x64 broght some type errors

The error below appeared in the building phase:
singleapplication.cpp(74): error C2664: 'BOOL GetUserNameW(LPWSTR,LPDWORD)' : cannot convert argument 1 from 'char [257]' to 'LPWSTR'

Shared memory problem on armhf

I've got a weird case on a armhf system. (see pbek/QOwnNotes#1089)
I'm not sure if it is the setup of the user or a problem with armhf in general.

Critical: SingleApplication: Unable to attach to shared memory block. ((null):0, (null))
Critical: "QSharedMemoryPrivate::initKey: unable to set key on lock" ((null):0, (null))

I had to add LIBS += User32.lib using msvc2017 Qt 5.9.2

This may be something funky/weird with my build setup but I had to add msvc:LIBS += User32.lib in my QMAKE project in addition to the msvc:LIBS += Advapi32.lib to use AllowSetForegroundWindow(DWORD(app.primaryPid())); with msvc 2017 64 bit building with Qt 5.9.2.

If others also have this issue it may make sense to add it to the .pri file.

SingleApplication doesn't work when two processes are started with millisecond delay

The commit 2dd9a4e says that it was fixed but doesn't work for me. On my case i use the same process as the main application and as a launcher to execute updates so both process are launched almost simultaniously.

I made the following demo to reproduce the issue:

#include <QCoreApplication>
#include <QDebug>
#include <QTimer>

#include <singleapplication.h>

int main(int argc, char *argv[])
{
    SingleApplication app(argc, argv);
    qDebug() << "process started, pid:" << QCoreApplication::applicationPid();

    QTimer::singleShot(3000, &app, SLOT(quit()));

    return app.exec();
}

Running the app twice with:

./demo &  ./demo

And get on stdout the following:

process started, pid: 27675
process started, pid: 27676

When the correct is to show only one message. I can reproduce the issue on Linux and macOS.

Sending message not always working

The issue

I found out the sendMessage() to fail (message not delivered) randomly (roughly in 50% of cases) if any of following is met:

  • Linux (Ubuntu) with Qt older than 5.6.3 (I edited QDataStream data version enumerations to 5.3 in the code)
  • MacOSX, probably for all Qt versions (I've tried with Qt 5.10).

I tested it with the example application "sending_arguments", just to be sure and yes, it's reproducible with that sample project.

The solution

I also found out a quick solution.

  1. Add #include <QThread> in singleapplication.cpp
  2. Add QThread::msleep(100); in the same file, in method sendMessage(), right after the line d->connectToPrimary( timeout, SingleApplicationPrivate::Reconnect );

Maybe not the most elegant way, but hey, at least it works. I'm not sure why Qt fails to wait required time and to be honest I did not have time to digg into it deeply enough.

Python implementation

Thanks for sharing this, Itay. Do you know if anyone has implemented your approach in Python?

Signal handlers used by SingleApplication on Unix-like systems prevent core dumps / crash reports when the process crashes

Because SingleApplication installs handlers for all the common signals, the default signal handler is never called in the event of (say) a segmentation fault, and hence the platform's usual crash reporting / core dump mechanism is never triggered. Instead, exit is called, which counts as a 'normal' process termination.

This is something I've noticed on Mac OS X, where the crash reporter doesn't get chance to do its job, but I think this would also apply if core dumps were enabled on Linux for example.

Also I believe related: I've seen some crash logs showing an infinite loop in SingleApplication::terminate, where it calls exit, which tries to free some allocated memory which happens to fail. This then calls abort and goes back to terminate again, and so on. In this case the process eventually dies from stack exhaustion, I assume, and we do get a log. But obviously this doesn't reveal much about the original source of the problem.

I think a solution would be to store the default signal handlers somewhere when they are replaced in crashHandler() and then reset them in the terminate function before re-raising the original signal, rather than calling exit.

Are you open to a pull request to pass secondary process arguments to the primary process?

It would be great if the arguments to the secondary process were passed to the master process so if I launched the secondary process like: MySingleApplication --arg1=value1 --arg2=value2, then the showUp() signal is modified to pass those along as a QStringList: showUp(QStringList const & args)

I would do the work for this as I need functionality like this. I believe QtSingleApplication used to do this.

Add CI tests

Let's add some automated tests as a safety net.

  • Appveyor for Windows?
  • TravisCI for Linux?

Partial Code Review and Feedback

Thanks for putting this lib/code together.
When browsing the code I noticed some things:

  1. There are numerous warnings from clang about c style casts (most/all of the pointer casts could just be static_casts, the others probably could be better served using QDataStream to avoid reinterpret casts), and about the possible use of an uninitialized value instanceId here, I don't think it can be uninitialized at that point but the fall through on the switch is confusing it (and most likely others).
  2. When writing the instanceId a quint32 is used (here) but only the little end byte is read back (here).
  3. The checksum quint16 is needlessly converted to string using QByteArray::number, and QByteArray::number is given an invalid parameter for the base (here and here). You pass in 256 for the second argument, but the Qt docs (here) mention that the base can be any value between 2 and 36.
  4. QLocalSocket::waitForReadyRead is used with the assumption that all data is available, according to the Qt docs not all data is guaranteed to be available see Qt's example here. Place in the code is here. In practice considering the amount of bytes written and the fact that it's a local socket this is likely to never fail, but it's not air tight to the documentation.

System wide not works on windows

I created an application this way:

SingleApplication app(argc, argv, false, SingleApplication::Mode::System);

but single application only works for a single user account on windows, I tested the calculator example you can open two instance with two different user account but each one can open only a single one.
Seems it requires that the shared memory key prefixed with "Global".
you can find more info about it here.
it should also be done for the SystemSemaphore.
I tried doing so by calling setNativeKey but no luck:

QSharedMemory *memory = new QSharedMemory();
memory->setNativeKey("Global\\" + d->blockServerName);
d->memory = memory;

the application can not create shared memory neither attach it.

GL.

Make it independent from Q*Application

Having looked at the code, it seems to me that the SingleApplication class has no reason for inheriting from one of the Q*Application classes. Making it inherit from QObject would avoid the need for the QAPPLICATION_CLASS define.

Is there any reason for this inheritance, or could it be removed?

Message Corruption with multiple secondary instances

Thanks for SingleApplication!
However, I had a problem with my particular use case. I have program myApplication which uses SingleApplication. I also have an otherApplication which calls many instances of myApplication in quick succession. The default interval for invocation is 500ms. At 2000ms everything works fine. At the default rate, however, the messages received by the primary will be lost, corrupted or mangled beyond recognition.

My solution to this was to add a bool parameter WAIT to shared memory. When a secondary instance sends a message it first acquires a QSystemSemaphore and sets WAIT true. It sends the message and then waits for WAIT to become false. When the primary is ready to receive another secondary message it emits a signal which connects to primary::slotReadyforNewInstance which sets WAIT false. The secondary then releases the semaphore allowing another secondary to send a message.

Only tested on windows and have not looked at corner cases of primary or secondary crashes

singleapplication.cpp.diff.txt
singleapplication.h.diff.txt
singleapplication_p.cpp.diff.txt
singleapplication_p.h.diff.txt

Hope you find this useful

Laris

Make it possible to get the username of the primary application

When a user starts the application and the application is already running, the running application gets the focus. But when the application was started on a different user account, I want to show a message box with a text like The application is already running by user .... Currently the application simply closes and the user is confused.

So a function like primaryUser() would be cool. And something like currentUser() or primaryStartedByDifferentUser().

Multiple instances of SingleApplication?

All stuff dealing with sharedMem object is completely needless and even potentially dangerous.
Why? Lets review some parts of code.

    QList<SingleApplicationPrivate*> SingleApplicationPrivate::sharedMem;
    QMutex SingleApplicationPrivate::sharedMemMutex;
// ...
        // This guarantees the program will work even with multiple
        // instances of SingleApplication in different threads.
        // Which in my opinion is idiotic, but lets handle that too.
        {
            sharedMemMutex.lock();
            sharedMem.append( this );
            sharedMemMutex.unlock();
        }

In fact, there can't be any guarantees whether program will work or not if there are multiple instances of SingleApplication. As mentioned in Qt documentation

For any GUI application using Qt, there is precisely one QApplication object, no matter whether the application has 0, 1, 2 or more windows at any given time.

and this rule is applied to QGuiApplication and QCoreApplication as well.
Moreover, from here

HP-UX: Only one attach to a shared memory segment is allowed per process. This means that QSharedMemory should not be used across multiple threads in the same process in HP-UX

That means you cant even properly create multiple instances of SingleApplication on systems like HP-UX.

Besides that, SingleApplicationPrivate::terminate signal handler is buggy (review man 7 signal in section Async-signal-safe functions), and use of signal() to set a signal's disposition to a function is not portable.
In general, setting signal handlers by library is not a good decision

SingleApplication::instanceStarted rarely triggers on Windows

It seems like the SingleApplication::instanceStarted is only triggered very rarely on Windows (~20-30%). On Linux, everything works perfectly, but on Windows the signal is simply not emitted.

Sample code:

#include <QApplication>
#include <QMainWindow>
#include <singleapplication.h>
#ifdef _WIN32
#include <Windows.h>
#endif

int main(int argc, char *argv[]) {
  SingleApplication app(argc, argv, true,
                        SingleApplication::Mode::User |
                            SingleApplication::Mode::SecondaryNotification);

  if (app.isSecondary()) {
#ifdef _WIN32
    AllowSetForegroundWindow(DWORD(app.primaryPid()));
    //app.sendMessage(QByteArray());
#endif
    return 0;
  }

  QMainWindow w;
  w.setFixedSize(300, 200);
  w.show();

  QObject::connect(&app, &SingleApplication::instanceStarted, &w, [&] {
    fprintf(stdout, "new instance started\n");
    fflush(stdout);
    w.show();
    w.activateWindow();
    w.raise();
  });

  return app.exec();
}

Interestingly, when I uncomment app.sendMessage(QByteArray());, then everything works fine and the signal is raised correctly in the primary instance.

Might be similar to #86, which was declared to be fixed since v3.1.5.

Question: why not just use named pipe on Windows and unix domain socket on Linux/Mac?

Question: why not just use named pipe on Windows and unix domain socket on Linux/Mac?

Maybe it is possible to implement the same functionality with just named pipe, without shared memory segment?
The main application tries to create named pipe or unix domain socket like /tmp/single-app-my-application.socket If it's already created- try to connect.

Signal handler is not safe

Signal handlers work like interrupts which means they need to be reentrant. According to the posix man page (http://man7.org/linux/man-pages/man7/signal-safety.7.html) only a few functions are safe to be used in a signal handler.

Looking at the C++ Standard (http://en.cppreference.com/w/cpp/utility/program/signal) neither delete nor exit() are safe.

I'm not sure what's the best way to handle the signals but it seems the only safe thing is to set a flag (std::atomic, std::sig_atomic_t, or a C equivalent) and then poll that flag in the main loop.

QTime elapsed is deprecated

Same as title, as the Qt 5.14.0 is released, the elapsed() signal in QTime has been marked as deprecated.

The solution to avoid receiving this warning is to use the QElapsedTimer
I think there's no need to change too much code, just add include and change the type of the timer from QTime to QElapsedTimer at here

AppImage on Ubuntu

I created a Qt application which is packed into an AppImage archive for distribution. Then the use clicks on the AppImage archive the application starts up.

I'm using SingleApplication to prevent secondary application to be fired. It works fine when I run the binary directly, but once binary and libraries are packed into an AppImage archive, it stops working.

Any idea? I tried to use SingleApplication::Mode::System and SingleApplication::Mode::User but none of them works. As I said, it stops working only when packed inside an AppImage format.

Regards,

Giovanni

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.