Qt compatibility
Feature Request
Do you want to solve a problem with your feature request? Please describe it.
I build Qt apps (console and GUI) and now have to build a terminal app with pretty IO, block graphics, etc. Instead of using ncurses I would really like to try this project. Curiously, the structure of this project seems to be very much in the style of Qt (which is great).
But, right from the start, finalcut needs to control the main application event loop, which would make it conflict with Qt doing the same. Has anyone succesfully combined finalcut and Qt5 ?
Your desired solution
An example of how to combine them (if possible)
Alternatives you have considered
Additional context
You must first determine whether an active X11/Wayland session exists. If this is the case, you must switch to the appropriate branch.
Here is a very simplified code that shows how this could be implemented in principle:
#include ...
int main (int argc, char argv[])
{
const std::string display_env = std::getenv("DISPLAY");
const std::string wayland_env = std::getenv("WAYLAND_DISPLAY");
if ( ! display_env.empty() || ! wayland_env.empty() )
{
// Launch Qt based GUI application
QApplication app (argc, argv);
QLabel label("Hello, World!");
label.resize(200, 100);
label.show();
return app.exec();
}
else
{
// Launch FINAL CUT based TUI application
finalcut::FApplication app{argc, argv};
finalcut::FMessageBox msg_box{&app};
msg_box.setText("Hello, World!");
return msg_box.exec();
}
}
Not sure I understand the answer., My program is a console only app, and doesn't care about any X11/Wayland sessions that may also be present.
By my console app does use threads and timers so I need to start the event queue in the main thread....but finalcut wants to do the same. If I understand your example correctly you are saying I don't need to start the Qt event loop?
Sorry, I really misunderstood that. I mistakenly thought that Qt should be used as a GUI toolkit. I don't know which Qt classes you are using in your code, so I can't really help you.
FINAL CUT also has a timer event, and instead of using Qt signals and slots, you can use FINAL CUT signals and callbacks.
Hope this helped a little.
The problem I see is that both Qt and FinalCut want to start an event loop. I don't think you can have two simultaneous event loops in the same thread since they compete for grabbing the idle time of the thread. But I'll experiment when I have time
I'll update this thread once I have some experience to share.
@ocgltd I was having a very similar situation in terms of using finalcut that I have a separate event loop
Common solution for those are:
- start every event loop in their own thread, then the cross-thread communication could be a problem and it's hard
- Replace internal event loop implementation, while finalcut doesn't provide this feature, Qt actually does via QCoreApplication::setEventDispatcher, which means you could implement qt event loop with finalcut/eventloop . However, FApplication is not based on finalcut's eventloop.. I'm not sure why is that, maybe because eventloop class comes later than FApplication. Maybe @gansm has an answer to this. I hope there could an example that Put FApplication and finalcut's event loop together. It means that currently even if you implement a finalcut eventloop based QAbstractEventDispatcher, it doesn't help to put FApplication + QCoreApplication together.
- On the other hand, finalcut (or any other TUI library), cares mostly only about stdin, which means you could run Qt's event loop and drive fapplication with QSocketNotifier (monitor stdin file descriptor). I'm not sure if that can make everything in finalcut works, One thing that I noticed is that if only monitor stdin, finalcut's timer may not be working, so you might want to have a timer to run one loop on FApplication regularly, or just use Qt's timer. I've seen other project integrate newt(a C tui lib) with glib main loop with this approach.
I had some success with (3) in the past so you might want to give it try.
#3 sounds promising, though I'm not too confident about doing that. Would you be able to post the code you used for #3 ?
@ocgltd Very preliminary demo, you can try to drag the window or click the button and it should work.
#include <unistd.h>
#include <QCoreApplication>
#include <QObject>
#include <QSocketNotifier>
#include <final/final.h>
class MyFApp : public finalcut::FApplication {
public:
using FApplication::FApplication;
private:
void processExternalUserEvent() override {
// We actually want to use processNextEvent, but it's not public.
// processExternalUserEvent is the last function called in
// processNextEvent So we simply call exitLoop here to use enterLoop to
// simulate processNextEvent.
exitLoop();
}
};
int main(int argc, char *argv[]) {
// Both will modify argc and consume argv correspondingly anyway.
// So just leave them as is.
QCoreApplication qapp(argc, argv);
MyFApp fapp(argc, argv);
// examples/hello.cpp
finalcut::FMessageBox mbox{&fapp};
const auto nl = finalcut::FString('\n');
const auto spacing = finalcut::FString(5, ' ');
const auto line = finalcut::FString(13, L'\U00002500');
mbox.setText(nl + spacing + "Hello, World!" + spacing + nl + line);
mbox.setCenterText();
mbox.show();
fapp.addCallback("last-dialog-closed", [&qapp]() { qapp.quit(); });
QSocketNotifier watcher(STDIN_FILENO, QSocketNotifier::Read);
QObject::connect(&watcher, &QSocketNotifier::activated,
[&fapp]() { fapp.enterLoop(); });
return qapp.exec();
}
I'm trying to understand your sample. It looks like....you are letting Qt to own the main event loop, and only tell FinalCut to poll for keyboard input once stdin shows a key waiting.
Does the FinalCut refreshing work? (Does it have it's own timers and eventloop that works seperately)?
@Uberseer I don't think that work and yes I do aware of that. I couldn't figure out a public API to get the finalcut's next timeout deadline since it seems to be private internal state, so I just did a stdin pull as only proof of concept.
You can add a QTimer code to drive finalcut's default 200Hz in the a similar way just like the stdin poll, but unless finalcut exposes more internal state, it would be still the partial implementation of fapp's event loop logic.
E.g. we may want to read time_last_event & next_event_wait to set the accurate timeout value to replicate the fapplication's logic. Right now we can only hard code it to match the finalcut's logic.
As someone new to FinalCut (I just found the project last week) I'm afraid this is over my head. I think I'll stay on the sidelines and maybe the project dev(s) can add something for Qt Compatibility / expose necessary API. From what you describe I would say Qt compatibility is really possible (in a production quality way) at this time.
I may dive in deeper to FinalCut in the future but I'll remain as a lurker for now.