Restoring or bringing to front Qt desktop application - c++

I have made my app into a single instance app using the RunGuard code found on this SO question:
Qt: Best practice for a single instance app protection
What I'd like to do is when the user tries to start the application while there is one running is to bring the existing running application to the front, and if minimised, restore it.
In my Delphi Windows programming days I used to broadcast a Windows message from the new application before closing it. The existing app would receive this and restore itself and come to the front.
Is something like this possible with Qt on Windows and Linux platforms?

Did you have any specific trouble with QtSingleApplication? It should be sufficient for what you want and will enable you to send a message to the running application. You just need a slot to get that message and if it matches what you expect then you restore it.
http://doc.qt.digia.com/solutions/4/qtsingleapplication/qtsingleapplication-example-trivial.html
The logview object is also set as the application's activation window. Every time a message is received, the window will be raised and activated automatically.

For some reason setActivationWindow() and activateWindow() don't work for me. This is my workaround:
#include <QWidget>
#include <qtsingleapplication.h>
class Window : public QWidget
{
Q_OBJECT
public:
Window(QWidget *parent = 0) : QWidget(parent) {}
public slots:
void readMessage(const QString &str) { showNormal(); }
};
int main(int argc, char *argv[])
{
QtSingleApplication instance(argc, argv);
Window *window = new Window;
window->show();
QObject::connect(&instance, SIGNAL(messageReceived(const QString &)), window, SLOT(readMessage(const QString &)));
if (instance.sendMessage(""))
return 0;
return instance.exec();
}
#include "main.moc"

In common, it is not possible without IPC. QtSingleApplication provide such IPC, but you will get extra dependency from QtNetwork module. (As #svlasov answered)
First problem that you will have: you can't raise any window of application if this application is not foreground. There are solutions for Windows and OS X, how to force raising of windows.

Related

Application with multiple windows in Qt

What is a good way to create application with multiple windows in Qt? Something like GIMP. I have already read this answer and it is not what I need.
I have two windows, one with controls and one with OpenGL inside. Right now I have something like this:
int main()
{
// some code
MainWindow mw;
mw.show();
GLWindow gw;
gw.show();
// ...
}
I don't like this for two reasons. First reason is when I start my application, window with OpenGL will be on top (because it is last to call show()) but MainWindow will be buried somewhere under all opened windows. What I need is both windows in front of everything (like GIMP), preferably with focus on MainWindow (I guess I can bring them to front, so that is minor issue). Second reason I don't like this is that my application will be closed completely only when I close both windows.
So I was thinking of having a reference to GLWindow inside MainWindow, and creating it from MainWindow.
Would that be a good way to create application with several windows?
EDIT: GLWindow inherits from QOpenGLWindow.
You are doing right, but with the following simple tricks, you can resolve both issues that cause you do not like your right method:
To activate both windows, just do as follows:
MainWindow mw;
mw.show();
mw.activateWindow();
GLWindow gw;
gw.show();
gw.activateWindow();
To resolve the quit problem, you have to override the closeEvent in both windows. To do that, add the following code into the header file of your both windows:
protected:
void closeEvent(QCloseEvent *event) override;
and in the implementation of the closeEvent, just write qApp->quit();. This way once you close either window, your application will terminate completely.
MainWindow.cpp
void MainWindow::closeEvent(QCloseEvent *event)
{
qApp->quit();
}
and
GLWindow.cpp
void GLWindow::closeEvent(QCloseEvent *event)
{
qApp->quit();
}
I'm not sure I completely understand the situation but, typically, you can make the 'secondary' widgets child dialogs of the QMainWindow. Given your example code that would be something like...
int main ()
{
// some code
MainWindow mw;
mw.show();
/*
* Secondary windows should be created with the QMainWindow mw
* as their parent.
*/
GLWindow gw(&mw);
/*
* Set the Qt::Dlaog window flag to `encourage' the QMainWindow
* and its children to behave as a group.
*/
gw.setWindowFlags(gw.windowFlags() | Qt::Dialog);
gw.show();
// ...
}
Now all widgets behave as a group (possibly subject to the window manager being used) and closing the QMainWindow will, by default, close the application.

Using QPainter with QCoreApplication

We have an application (QCoreApplication) that takes some images as input, does something to them, and exports them again. We now need to add some text to the images, and tried to do this with the QPainter class. It all worked well when using it in one of our other apps (using QApplication), but not in our main QCoreApplication app.
Here is the code:
void drawTextOnImage(QImage* image, const QString& text, const QFont& font)
{
QPainter p;
if (!p.begin(image)) return;
p.setFont(font);
p.drawText(image->rect(), Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, text);
p.end();
}
The application crashes on the drawText line.
Any ideas?
It is a very simple text, so suggestions without using Qt will also be appreaciated.
When using classes from "Qt Gui" like QPainter, you are supposed to use a QGuiApplication, not a QCoreApplication.
You might get lucky and be able to make some GUI stuff works while using only a QCoreApplication. But as you have discovered, it makes your application very brittle. Some classes like QPixmap will print an error message, but others will just crash.
The same is applicable with "Qt Widget": if you use a widget related class, you must use a QApplication.
Note that since QApplication inherits QGuiApplication, if you have a QApplication you can use "Qt Gui".
In case you need to run a non-GUI application on something without a windowing system, you need, aside from creating an instance of QGuiApplication, to also choose an appropriate Qt platform.
For me, offscreen platform worked fine. I was generating images with textual elements and saving them to files on a headless Raspberry Pi. My code then was like the example below. Note that setenv is a POSIX function and may need a replacement on Windows, though I'm not sure whether windowless Windows is a thing at all.
#include <stdlib.h>
#include <QImage>
#include <QPainter>
#include <QGuiApplication>
int main(int argc, char** argv)
{
setenv("QT_QPA_PLATFORM","offscreen",1);
QGuiApplication app(argc,argv);
QImage img(128,128, QImage::Format_RGB888);
img.fill(Qt::white);
QPainter p(&img);
p.drawText(QPoint(0,64), "Works!");
img.save("/tmp/test.png");
}

Observe changes in QSharedMemory

I have a QSharedMemory to prevent that two processes of my application are running at the same time. Process A sets the QSharedMemory to "locked" when started. Now my process B sets a value like "please come back to foreground".
Is there an easy way for process A to observe changes in the QSharedMemory, i.e. avoids implementing a stupid pulling timer?
Here we are: QSystemSemaphore
Like its lighter counterpart QSemaphore, a QSystemSemaphore can be accessed from multiple threads. Unlike QSemaphore, a QSystemSemaphore can also be accessed from multiple processes.
Like QSharedMemory, QSystemSemaphore uses a key-based access method.
Instead of using shared memory, the process could open a QLocalSocket to a named local server, and when it fails, open a QLocalServer. All subsequent processes will success to open the socket to the server, and can communicate with it. That's probably the simplest, most portable way of accomplishing the job.
You can also use QtSingleApplication, iff it has been ported to Qt 5.
To answere your question: No, QSharedMemory does not have such a feature.
If you just want to have a "single instance" application, you can use https://github.com/Skycoder42/QSingleInstance.
It makes shure you have only 1 instance of you application at a time, can automatically bring the active window to the front and allows you to pass parameters from the new process to the running one.
Simple example:
#include "mainwindow.h"
#include <QApplication>
#include <QMessageBox>
#include <qsingleinstance.h>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QSingleInstance instance;
MainWindow *w = NULL;
instance.setStartupFunction([&]() -> int {
w = new MainWindow(NULL);
instance.setNotifyWindow(w);
w->show();
return 0;
});
QObject::connect(qApp, &QApplication::aboutToQuit, [&](){
delete w;
});
QObject::connect(&instance, &QSingleInstance::instanceMessage, [&](QStringList args){
QMessageBox::information(w, "Message", args.join('\n'));
});
return instance.singleExec();
}
This will show the mainwindow, just like you woudl expect. If the application is run a second time, the currently running mainwindow will be raised to the foreground and a messagebox with the arguments will be shown.
Note: This example uses the QWidgets, but the QSingleInstance can be used with a gui or core application, too.

Qt event when anything changed on the window/screen + Screenshot

I'm thinking of extending a QT4 application with some debug possibilities, to make it easier analyzing customer issues. The application already has a "Debug" mode, when this is enabled, a lot of log entries generated, which is hard to read.
What I would like to achive is taking a screenshot of the application, whenever something is changed on the GUI. I know that it may take a lot of pictures, but generally Debug mode is not enabled for a long time. The problem is I cannot find such an event/signal. So I have two question:
Is there such an event I could subscribe? I mean, an event that is
fired whenever anything changes on the screen.
Can I take a screenshot of the application using Qt?
Thanks in advance!
I'd do it using an event filter and a QTimer, something like this:
class MyEventFilter : public QObject
{
public:
MyEventFilter() : _screenshotPending(false) {/* empty */}
virtual bool eventFilter(QObject * o, QEvent * e)
{
if (e->type() == QEvent::Paint)
{
if (_screenshotPending == false)
{
// we'll wait 500mS before taking the screenshot
// that way we aren't trying to take 1000 screenshots per second :)
_screenshotPending = true;
QTimer::singleShot(500, this, SLOT(TakeAScreenshot()));
}
}
return QObject::eventFilter(o, e);
}
public slots:
void TakeAScreenshot()
{
_screenshotPending = false;
// add the standard Qt code for taking a screenshot here
// see $QTDIR/examples/widgets/desktop/screenshot for that
}
private:
bool _screenshotPending; // true iff we've called QTimer::singleShot() recently
};
int main(int argc, char ** argv)
{
MyEventFilter filter;
QApplication app(argc, argv);
app.installEventFilter(&filter);
[...]
return app.exec();
}
Generally, when some widget changes Qt needs to repaint it, so the event you would be interested in is QEvent::Paint. The problem here is that there will be tons of these events for widgets that overlap each other. You can override QApplication::notify() to catch all paint events before they are even delivered to receivers.
As for making screenshots of Qt application - there are several similar questions here on SO, for example screenshot of a qt application from inside the application or Taking screenshot of a specific window - C++ / Qt
Here is also a thread discussing dumping widgets to images in paintEvent().
As for your second question, here is some of my old code that can take a screenshot of a window. You can use this code like so:
HDC WinDC = GetDC(HWND_OF_YOUR_WINDOW);
HBITMAP image = ScreenshotUtility::fromHDC(WinDC);
Then you can convert the HBITMAP to a Qt Pixmap object and work with it how you like: QPixmap pixmap = QPixmap::fromWinHBITMAP(image);.
EDIT: this is Windows-specific code, not sure what the equivalent on other systems may be.

Headless QT4 OpenGL Application

I'm working on creating a headless console application in QT4 that does some OpenGL rendering and then ships the result out across the network via a websocket. I have all of the rendering and network code running (assuming that I have a GUI), but I am having some trouble transitioning to a headless application. Is it possible to create a QGLContext without having a window?
Reading on the web hasn't turned up much, but from what I have gathered you can create a QGLPixelBuffer which is a valid QPaintDevice. It seems to create its own private QGLContext that it uses for hardware accelerated drawing. The problem that I am having with this route is that I need access to it's underlying QGLContext so that I can share it with another thread (network thread for fast DMA texture transfers out of the rendered scene). Included below is a small prototype. Any ideas?
Application.h
/**
#file
#author Nikolaus Karpinsky
*/
#ifndef _APPLICATION_H_
#define _APPLICATION_H_
#include <QCoreApplication>
#include <QTimer>
#include "MainController.h"
#endif // _APPLICATION_H_
Application.cpp
#include "Application.h"
int main(int argc, char **argv)
{
// Setup our console application with an event loop
QCoreApplication app(argc, argv);
// Create and initialize our controller
MainController controller;
controller.Init();
QObject::connect(&controller, SIGNAL( Finished() ), &app, SLOT( quit() ), Qt::QueuedConnection);
// This will put start on top of the event loop
QTimer::singleShot(0, &controller, SLOT( Start() ));
// Finally start up the event loop
return app.exec();
}
MainController.h
/**
#file
#author Nikolaus Karpinsky
*/
#ifndef _MAIN_CONTROLLER_H_
#define _MAIN_CONTROLLER_H_
#include <QObject>
#include <QGLWidget>
#include <QGLPixelBuffer>
#include <QGLFramebufferObject>
#include <memory>
using namespace std;
class MainController : public QObject
{
Q_OBJECT
private:
unqiue_ptr<QGLPixelBuffer> m_mainBuffer;
//unique_ptr<QGLContext> m_mainContext;
public:
MainController();
void Init(void);
public slots:
void Start(void);
void Close(void);
signals:
void Finished(void);
};
#endif // _MAIN_CONTROLLER_H_
MainController.cpp
#include "MainController.h"
MainController::MainController() : QObject()
{ }
void MainController::Init(void)
{
m_mainBuffer = unique_ptr<QGLPixelBuffer>(new QGLPixelBuffer(800, 600));
bool has = buffer->hasOpenGLPbuffers();
bool current = buffer->makeCurrent();
bool valid = buffer->isValid();
// Now I need to get access to the context to share it with additional threads
// m_mainContext = unique_ptr<QGLContext>(new QGLContext(buffer.getContext()));
}
void MainController::Start(void)
{
}
void MainController::Close(void)
{
// This will tell the event loop that we are done and close the app
emit( Finished() );
}
Is it possible to create a QGLContext without having a window?
Yes, but there is a catch…
Reading on the web hasn't turned up much, but from what I have gathered you can create a QGLPixelBuffer which is a valid QPaintDevice.
Yes, but that PBuffer still needs to talk to the GPU. And in Linux the usual way to talk to the GPU is through the X server. So you actually need an X server, using the GPUs drivers, to be launched and the active VT so that a PBuffer can work on the GPU.
Hopefully there will be a new ABI/API to GPUs soon, that allows you to create offscreen render contexts on a GPU without having an X server around.
The problem that I am having with this route is that I need access to it's underlying QGLContext so that I can share it with another thread (network thread for fast DMA texture transfers out of the rendered scene).
Unfortunately the Qt developers have only limited knowledge about OpenGL, as it seems. Several things that are perfectly possible with OpenGL and well specified are not possible with Qt for no apparent reason. For example you can have an arbitrary number of contexts using a single drawable. But you can also use single context on an arbitrary number of (compatible) drawables by rebinding it. Neither is supported by Qt and a clear design flaw. I'm struggling with this myself right now.
Ok, so after some playing around I found a good enough solution. Currently I am running my application as a QApplication vs QCoreApplication. From here I create a QGLWidget on the GUI thread and then immediately call updateGL() on the widget which creates and initalizes the OpenGL context. Assuming I don't ever make the app visible it runs "headless" but still gets the QT needed window handle from X or Explorer.
Going a bit deeper, I also needed to get shared QGLContexts on other threads. To make copies of the context from the QGLWidget I simply create a QGLWidget using the deprecated constructor where you can specify a painter (QGLWidget) and then create using the QGLWidgets context. I posted an example below to show. Using this I can write textures in one thread and process in another while keeping the app "headless". Thanks for the help datenwolf.
shared_ptr<QGLContext> MainController::MakeSharedContext(void)
{
shared_ptr<QGLContext> sharedContext(nullptr);
if(nullptr != m_mainContext)
{
// m_mainContext is: shared_ptr<QGLWidget>
sharedContext = shared_ptr<QGLContext>( new QGLContext(m_mainContext->format(), m_mainContext.get( ) ) );
bool created = sharedContext->create( m_mainContext->context( ) );
Utils::AssertOrThrowIfFalse(created, "Unable to create a shared OpenGL context" );
}
return sharedContext;
}