Screen locker in Qt - qt

Are there any Qt based screen lockers on linux systems ?
i.e. 4 pin digit or password screen locker ?
Any reference will be greatly appreciated.

On linux, the screen locking is done by the screensavers, and the password is the one from the user linux account.
You can use QProcess to run a command line and check if it was successful:
gnome-screensaver-command --lock
xscreensaver-command --lock
qdbus org.freedesktop.ScreenSaver /ScreenSaver Lock
qdbus org.gnome.ScreenSaver /ScreenSaver Lock
xlock
And/or use QtDBus module to do the same thing
// Tries to lock the screen and returns true if successful
bool LockScreenWithDBus() {
QDBusConnection bus = QDBusConnection::sessionBus();
if(!bus.isConnected())
return false;
QStringList services;
services << "org.freedesktop.ScreenSaver"
<< "org.gnome.ScreenSaver"
// These last two are probably not necessary, because kde uses freedesktop
// conventions for dbus
<< "org.kde.ScreenSaver"
<< "org.kde.krunner";
foreach(QString service, services) {
QDBusInterface screenSaverInterface(service, "/ScreenSaver",
QString(), bus);
if (!screenSaverInterface.isValid())
continue;
QDBusReply<void> reply = screenSaverInterface.call("Lock");
if (reply.isValid())
return true;
}
return false;
}

You can create a top level FrameLess Semi transparent QWidget of Screen Height and screen width and in its center place your Textbox for password asking.

Related

QGuiApplication::commitDataRequest: QML window is not painted

I'm trying to add quit confirmation message at OS shutdown according to this example:
https://doc.qt.io/qt-5/qsessionmanager.html#allowsInteraction
I interact with the user via QML interface. It is asynchronous, so I use slots/signals. And I use additional QEventLoop to stay inside of QGuiApplication::commitDataRequest call while interacting with the user.
The trouble is that after I shutdown OS (Windows 10) - my app prevents OS to shutdown and it's good, but its screen is just white, or contains old state without the confirmation dialog. I need to hide/restore window or change its size, or do some mouse clicks inside of it to force it repaint. When it repaint all is OK and my confirmation dialog is there.
Is this a bug? Is there a workaround?
This is the code I use:
void AppQuitConfirmationAtOsShutdownManager::onCommitDataRequest(
QSessionManager &m)
{
if (!m_ui->isConfirmationRequired())
return;
if (!m.allowsInteraction())
return;
bool isConfirmed = true;
QEventLoop loop;
qtconnect(m_ui.data(), &AppQuitConfirmationUiManager::confirmationResult,
&loop, [&](bool confirmed)
{
isConfirmed = confirmed;
loop.quit();
},
Qt::QueuedConnection);
m_ui->requestConfirmation();
loop.exec();
m.release();
if (!isConfirmed)
m.cancel();
}

Project hangs on QProcess::start when starting QtAssistant

I am using QProcess::start to launch Qt Assistant with my custom help project file. It works fine until i load project(not help project file) to my programm. Programm generates images from specific data using custom library. Even when all processes ends and i see generated images and nothing else happens, when i trying to launch Qt Assistant, my programm hangs at QProcess:start function when trying to start process. The code is:
show() function(public):
if (!run())
return false;
QByteArray ba("setSource ");
ba.append("qthelp://insyn_help/doc/");
proc->write(ba + page.toLocal8Bit() + '\n');
return true;
run() function(private):
if (!proc)
proc = new QProcess();
if (proc->state() == QProcess::Running)
return true;
QString app = QString(QT_BIN_DIR) + QDir::separator() + QString("assistant");
QString path = QString(PREFIX) + QString(HELP_INSTALL_PATH) + QString("/help_project.qhc");
QStringList args;
args << QLatin1String("-collectionFile")
<< QLatin1String(path.toLatin1())
<< QLatin1String("-enableRemoteControl");
QFileInfo help_project(path);
if (help_project.exists()) {
proc->start(app,args);
if (!proc->waitForStarted()) {
m_exitCode = 1;
emit closed();
return false;
}
}
This code is a part of AssistantLauncher class which was registered using qmlRegisterType and added to main.qml as a member of application window. My programm doesn't touch it anywhere (except calling a method show()). It is separate object (except it is a part of appWindow). The question is why does the process can not start only after my programm did some work? And why QProcess::start even dont have timeout.
UPD: I moved proc->start(app,args); to the child process, which i getting by using fork() and now my programm hangs on pid_t child = fork(). So the problem is that new process can not be created.
The answer is to do not use fork() because it is dangerous in big projects. More at http://www.evanjones.ca/fork-is-dangerous.html . posix_spawn also hangs my project. Now i decided to fork() new process at the beginning and send commands to it through the pipe.

Properly using Qt QProcess

I'm considering to use QProcess to call a command line app (gpio) multiple times. Every time user clicks a button then a command is issued.
And the app output will be monitored and redirected to screeen. The code looks like the following.
void Gpio::command(QString argument)
{
// if(process)
// delete process;
process = new QProcess(this);
connect(process, SIGNAL(started()), this, SLOT(onStart()));
connect(process, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(onFinish(int,QProcess::ExitStatus)));
connect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(readGpio()));
QString program("gpio");
QStringList list = argument.split(" ");
process->start(program, list);
}
Question: Should I delete process? Doing so I got:
QProcess: Destroyed while process is still running.
Monitoring exitCode and exitStatus I see they are always 0.
This question concerns more about the proper use of QProcess while "QProcess and shell : Destroyed while process is still running" focus on the specific error.
as you don't want to run multiple processes concurrently (as per the comments), you don't need to create / delete the QProcess multiple times.
gpio.h
QProcess* m_gpioProcess;
gpio.cpp file
Gpio::Gpio(.....),
.....(),
m_gpioProcess(new QProcess(this))
{
m_gpioProcess->setProgram("gpio");
connect(m_gpioProcess, SIGNAL(started()), this, SLOT(onStart()));
connect(m_gpioProcess, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(onFinish(int,QProcess::ExitStatus)));
connect(m_gpioProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(readGpio()));
}
void Gpio::command(const QString& args)
{
if (m_gpioProcess->state() != QProcess::NotRunning) {
qDebug() << "Process already running, ignoring the request";
return;
}
m_gpioProcess->setArguments(args.split(" "));
m_gpioProcess->start();
if (m_gpioProcess->waitForStarted()) {
qDebug() << "Process started with arguments:" << m_gpioProcess->arguments();
}
}
if you want to prevent user clicking the button multiple times, consider enabling / disabling the button as per m_gpioProcess state.
for Qt 4.8, just remove this line
m_gpioProcess->setProgram("gpio");
and this line
m_gpioProcess->setArguments(args.split(" "));
and change this line
m_gpioProcess->start();
to
m_gpioProcess->start("gpio", args.split(" "));
Well, It seems I was forgetting process->waitForFinished(); after the call to start. This seems to solve the problem.
add following code maybe helpful:
process->close();

QDialog::accept quits Main Application

I have a ClientSocket Class which is a TcpSocket in a certain state of conversation I need to ask the user to enter a Communication password. So I've created a Dialog DG::ChallangeDialog . in DG::ChallangeDialogs ctor I've
ui->setupUi(this);
QPushButton* okButton = ui->buttonBox->button(QDialogButtonBox::Ok);
if(okButton != 0x0){
okButton->setText("Challange");
}
QObject::connect(this, SIGNAL(accepted()), this, SLOT(acceptedSlot()));
acceptedSlot again emits a signal challanged(QString)
void ChallangeDialog::acceptedSlot(){
QString text = ui->passBox->text();
emit challanged(text);
}
in ClientSocket I do
case Hallo:{
if(m->message().startsWith("welcome")){
DG::ChallangeDialog* dlg = new DG::ChallangeDialog;
dlg->setModal(true);
connect(dlg, SIGNAL(challanged(QString)), this, SLOT(challanged(QString)));
dlg->exec();
/*
DG::MessagePacket* res = new DG::MessagePacket((int)Hallo);
res->setMessage("challange");
send(res);
state = Challange;
*/
}
}break;
In ClientSocket::challange slot I send a Message challange (text) over the socket and store the password.
and I expect the Dialog to hide there and the normal socket conversation to continue. and after the Dialog is accepted or rejected the main application quits (It quits it doesn't crash). Why ?
My Application has no Other Widgets. I just works like an QCoreApplication. But still I've used QApplication cause I've some GUI Needs.
Is this the only window that is shown at this time? If so, I would guess that your QApplication instance is set to quit when the last window is closed. It is true by default.
If this is the case, you should explicitly set this to false before showing any windows.

To connect Gstreamer with Qt in order to play a gstreamer video in the Qt Widget

I tried using phonon to play the video but could not succeed. Off-late came to know through the Qt forums that even the latest version of Qt does not support phonon. That's when I started using Gstreamer. Any suggestions as to how to connect the Gstreamer window with the Qt widget? My aim is to play a video using Gstreamer on the Qt widget. So how do I link the Gstreamer window and the Qt widget?
I am successful in getting the Id of the widget through winid().
Further with the help of Gregory Pakosz, I have added the below 2 lines of code in my application -
QApplication::syncX();
gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(sink), widget->winId());
However am not able to link the Qt widget with the gstreamer video window.
This is what my sample code would look like :-
int main(int argc, char *argv[])
{
printf("winid=%d\n", w.winId());
gst_init (NULL,NULL);
/* create a new bin to hold the elements */
bin = gst_pipeline_new ("pipeline");
/* create a disk reader */
filesrc = gst_element_factory_make ("filesrc", "disk_source");
g_assert (filesrc);
g_object_set (G_OBJECT (filesrc), "location", "PATH_TO_THE_EXECUTABLE", NULL);
demux = gst_element_factory_make ("mpegtsdemux", "demuxer");
if (!demux) {
g_print ("could not find plugin \"mpegtsmux\"");
return -1;
}
vdecoder = gst_element_factory_make ("mpeg2dec", "decode");
if (!vdecoder) {
g_print ("could not find plugin \"mpeg2dec\"");
return -1;
}
videosink = gst_element_factory_make ("xvimagesink", "play_video");
g_assert (videosink);
/* add objects to the main pipeline */
gst_bin_add_many (GST_BIN (bin), filesrc, demux, vdecoder, videosink, NULL);
/* link the elements */
gst_element_link_many (filesrc, demux, vdecoder, videosink, NULL);
gst_element_set_state(videosink, GST_STATE_READY);
QApplication::syncX();
gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(videosink), w.winId());
/* start playing */
gst_element_set_state (bin, GST_STATE_PLAYING);
}
Could you explain more in detail about the usage of gst_x_overlay_set_xwindow_id() wrt my context?
Could I get any hint as to how I can integrate gstreamer under Qt?
Please help me solve this problem.
I just did this same thing using python. What I had to do was connect to 'sync-message::element' on the bus and listen for a message called 'prepare-xwindow-id' (disregard the name as it works on all platforms, not just X11) sent after the video sink is setup. It sends you the sink inside that message, and that is where you pass it the window id.
The sample code given above will link GStreamer video window to QtWidget provided the elements are linked correctly.
filesrc should be linked to the demuxer
decoder should be linked to the filesink
Finally, the demuxer should be linked to the decoder at runtime
// link filesrc to demuxer
gst_element_link(filesrc,demux)
// link vdecoder to filesink
gst_element_link_many(vdecoder,filesink,NULL)
/*
The demuxer will be linked to the decoder dynamically.
The source pad(s) will be created at run time,
by the demuxer when it detects the amount and nature of streams.
Connect a callback function which will be executed
when the "pad-added" is emitted.
*/
g_signal_connect(demux,"pad-added",G_CALLBACK(on_pad_added),vdecoder);
// callback definition
static void on_pad_added(GstElement* element,GstPad* pad,gpointer* data)
{
GstPad* sinkpad;
GstElement * decoder = (GstElement*)data;
GstCaps* caps;
GstStructure* str;
gchar* tex;
caps = gst_pad_get_caps(pad);
str = gst_caps_get_structure(caps,0);
tex = (gchar*)gst_structure_get_name(str);
if(g_strrstr(tex,"video"))
{
sinkpad = gst_element_get_static_pad(decoder,"sink");
gst_pad_link(pad,sinkpad);
gst_object_unref(sinkpad);
}
}
http://cgit.freedesktop.org/gstreamer/gst-plugins-base/tree/tests/examples/overlay
has a minimal Qt example.
In your code, you should probably set the window ID before you do the state change to ready (I'm not 100% sure this is the problem though).
For playback, you should idally use the playbin2 element, something like this (completely untested):
GstElement *playbin, *videosink;
gchar *uri;
playbin = gst_element_factory_make ("playbin2", "myplaybin");
videosink = gst_element_factory_make ("xvimagesink", NULL);
g_object_set (playbin, "video-sink", videosink, NULL);
uri = g_filename_to_uri ("/path/to/file", NULL, NULL);
g_object_set (playbin, "uri", uri, NULL);
g_free (uri);
/* NOTE: at this point your main window needs to be realized,
* ie visible on the screen, and you might need to make sure
* that your widget w indeed has a 'native window' (just some
* things to check for if it doesn't work; there should be Qt
* API for this kind of thing if needed) */
QApplication::syncX();
 gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(videosink), w.winId());
gst_element_set_state (playbin, GST_STATE_PLAYING);
.. check for messages like error/statechanges/tags/eos on pipeline/playbin bus
A project wrapping gstreamer into usable C++/Qt classes including example code:
http://code.google.com/p/qbtgstreamer/
I don't know about a direct approach, as I am not familiar with gstreamer itself.

Resources