Replacing custom events in GTK4 - c++

In one of my projects in GTK3, I am using custom events for communication between threads. One thread is the main OS thread on which the event loop is running. The other one is a non main thread that is doing some internal application specific initialization. The condition is that the first GTK window shall be created, only after the application is initialized. However, I don’t want to delay the main thread entering the event loop for some design related reasons.
Therefore, the main thread enters the event loop as soon as GTK is initialized and the non main thread needs to intimate the main thread when first window can be created. For this intimations I am using custom events in GTK3 (it can be created although I am not sure it is recommended or not).
The code snippet for the non main thread creating custom event is as below -
GdkEvent * createwinevent;
// Create and post custom event to start GTK Window creation
createwinevent = gdk_event_new ((GdkEventType) CREATE_WINDOW);
// CREATE_WINDOW is an enum defined by the application
gdk_event_put (createwinevent);
In the main thread, I am using g_idle_timeout to check the event queue intermittently and handle the custom events.
In GTK4 however, GdkEvents have been made read-only. Can custom events still be created in GTK4 somehow? If not, is there any other mechanism I can use in GTK4 to pass message between threads?
Reading through GTK4 materials could not find anything to support custom events.

Reading from the Migrating from Gtk 3.x to GTK4 (Section Adapt to GdkEvent API changes):
Direct access to GdkEvent structs is no longer possible in GTK 4.
GdkEvent is now a strictly read-only type, and you can no longer
change any of its fields, or construct new events. All event fields
have accessors that you will have to use.
So it think what you are doing is no longer possible in GTK4.

Related

Can a PostMessage to the same window be done from multiple threads simultaneously?

I'm using a dispatching mechanism in my Win32 application where non-main threads can post a piece of work wrapped in an std::function for later execution on the main thread. This is realized by creating a hidden window from the main thread, and using its window procedure to filter out these pieces of work, and then executing them. Background threads then use a PostMessage() call on this window, with a custom message id (>WM_USER), while wrapping a heap-allocated std::function in the LParam.
This approach appears to be conceptually sound, but I have some reservations regarding thread-safety. MSDN makes no mention that I found, indicating whether multiple threads may or may not simultaneously post a message to the same window. Is there a definitive verdict?

Qt : qt cannot send events to objects owned by a different thread - Why

I am developing an application with Qt whereby I want to update my GUI from another unrelated class with functions executing in a different thread.
I registered a callback function from the Qt GUI class to the other class using standard C++ constructs std::function and std::bind.
On trying to execute the GUI callback function from the other class, my program crashes with "qt cannot send events to objects owned by a different thread".
My questions are, what is happening here exactly. Why is it not permissive to communicate between two threads like this. Is it possible to resolve this in some way , or does Qt just not allow other unrelated functions to update the GUI in this way ?
For information , I am using portaudio libraries on windows. It executes a callback in a different thread. When I receive audio, I try to update my GUI.
Thank you in advance
You're probably being thrown off by the "send events" phrase. In Qt, this phrase has a strict technical meaning. Namely:
to send events means to use QCoreApplication::sendEvent, which then immediately invokes QObject::event on the receiver. It is an error to send events when the sending and receiving threads are different.
to post events means to use QCoreApplication::postEvent, which posts the event to the receiving object thread's event queue. The QObject::event on the receiver is invoked later by the receiver thread's event loop.
When objects live in different threads, you're not allowed to send events, only to post them. This points to the underlying cause of your issue/
Any method you access on a QWidget or a derived class must be accessed on its thread(), i.e. the main thread. Everything inside of QWidget can use sendEvent freely as the sending thread and receiving object's thread are identical by contract. By calling QWidget methods from the wrong thread, you break that contract by indirectly using sendEvent and thus fail.
Only methods that you yourself have implemented and are thread-safe can be called from other threads - and they can't use sendEvent.

PPL Task - Continuation in UI thread for desktop application

I would like to use a ppl task to do some work in the background, and, upon completion, show the result in a window. In my case the UI-framework is MFC. The structure would be:
using namespace concurrency;
create_task([] {
// this can be run in any thread, shouldn't be the UI thread
// do real work here
return 42;
}).then([](int n)
{
// this should be run on the UI thread
// ... open a MFC window to display results
});
The thing is, a non Windows Store app doesn't allow to specify the task_continuation_context. Instead, the runtime decides which context will be used (see task_continuation_context Class).
Can I rely on the runtime to reliably figure out that it needs to run the continuation on the UI thread? Is there a reasonable workaround to achieve what I want - without blocking the UI thread?
Update: Playing around showed that the runtime will not run the continuation on the UI thread. So, is it impossible?
What I did to solve this was to create a Dispatcher class and a message-only window, which is a member of the Dispatcher. The Dispatcher must be constructed (I used a singleton) from the main thread such that the main thread takes care of the messages which are sent to the message-only window. I can pass a std::function to my Dispatcher::ExecuteInMainThread function. The Dispatcher will then invoke SendMessage on the message-only window, passing in the pointer (unfortunately only a pointer will be possible) to the std::function. The only message handler I need in the message-only window will then invoke the function I passed in - within the main thread.
This Dispatcher can be used in the task continuation to execute a std::function in the main thread.

Qt GUI event recording and playback

I'm attempting to implement a simple, lightweight system for recording Qt GUI events and playing them back from a script. I thought this would be fairly straightforward using the magic of Qt's event system, but I'm running into a problem I don't understand.
Here's quick summary of what I'm doing:
RECORDING:
I use QApplication.instance().eventFilter() to capture all GUI events I'm interested in* and save them to a Python script, in which each step looks something like this:
obj = get_named_object('MainWindow.my_menubar')
recorded_event = QMouseEvent(2, PyQt4.QtCore.QPoint(45, 8), 1, Qt.MouseButtons(0x1), Qt.KeyboardModifiers(0x0))
post_event(obj, recorded_event)
PLAYBACK:
I simply execute the script above, in a worker (non-GUI) thread. (I can't use the GUI thread because I want to keep sending scripted events to the application, even if the 'main' eventloop is blocked while a modal dialog eventloop is running.)
The important stuff happens in my post_event() function, which needs to do two things:
First, call QApplication.postEvent(obj, recorded_event)
Wait for all events to finish processing:**
Post a special event to the same eventloop that obj is running in.
When the special event is handled:
Call QApplication.processEvents()
Set a flag that tells the playback thread it's okay to continue
After the second part is complete, my expectation is that all effects of the first part (the recorded event) have completed, since the special event was queued after the recorded event.
The whole system mostly seems to work just fine for mouse events, key events, etc. But I'm having a problem with QAction handlers when I attempt to playback events for my main QMenuBar.
No matter what I try, it seems that I can't force my playback thread to block for the completion of all QAction.triggered handlers that result from clicking on my QMenu items. As far as I can tell, QApplication.processEvents() is returning before the QAction handler is complete.
Is there something special about QMenu widgets or QAction signals that breaks the normal rules for QApplication.postEvent() and/or QApplication.processEvents()? I need a way to block for the completion of my QMenu's QAction handlers.
[*] Not every event is recorded. I only record spontaneous() events, and I also filter out a few other types (e.g. Paint events and ordinary mouse movements).
[**] This is important because the next event in the script might refer to a widget that was created by the previous event.
I think your problem might best be served by using QFuture and QFutureWatcher (that is, if you're using the QtConcurrent namespace for threads, and not QThreads). Basically, the Qt Event handling system does NOT necessarily handle events in the order they're posted. If you need to block until a certain action is completed, and you're doing that action in a separate thread, you can use the QFuture object returned by QtConcurrent::run() with a QFutureWatcher to block until that particular thread finishes its processing.
Something else to consider is the way you handle events. When you use QApplication.postEvent(), the event you create gets added to the receiver's event queue to be handled later. Behind the scenes, Qt can reorder and compress these events to save processor time. I suspect this is more your problem.
In your function which handles playback, consider using QCoreApplication::processEvents(), which will not return until all events have finished processing. Documentation for QCoreApplication is here.
QMenu widgets and QAction signals are a special case. QMenu has an exec() function, normally used for popups. I suspect (but I don't know for sure) that QMenuBar would use this mechanism when it opens a regular pull-down menu. The docs are not clear about this, but Menus act a lot like dialog boxes in that they block all other user activity - how would Qt do this except by giving menus their own event loop? I can't fill in all the blanks from the information in your post, but I don't see how your playback thread would cope with a new event loop.

How do I create Modal dialog in worker thread(Non-UI thread)?

I have written a sample MFC application in which there are two threads:
-Main thread ( UI thread)
-Worker thread ( non-UI thread)
I have a specific requirement to create a Modal dialog in Non-UI ( worker thread).
When I create the CDialog object and call DoModal on the same, it works. The dialog gets created and acts as Modal to the application. ( Win XP SP2 machine) But this does not work in Windows 2003 server machine.
The behavior in 2003 server is that, the Modal Dialog goes behind the application main Window and dialog will be brought to front only when I click on Main Window. It is not acting as Modal dialog to my application.
What could be the problem -- any ideas?
If creating UI controls in non-UI thread is the issue then is there any Win32 API which will allow me to link my worker thread to Main UI thread such that DoModal happens in Main thread. I tried AttachThreadInput but it is not working.
There is no reliable way to spread GUI modality across multiple threads. Every window is represented by an object referenced through a HWND which in turn has thread affinity. This is a left-over from the 16-bit days of Windows, where there was no multi threading. Consequently the HWNDs are not protected against concurrent access. The Old New Thing has an excellent series on "Thread affinity of user interface objects" (Part 1 2 3 Addendum).
Modality is implemented by first enabling the dialog window and then disabling its parent. The first step is safe while the second attempts to disable a window from a thread which is not the window's owning thread. Since en-/disabling windows modifies the object referenced through the HWND it represents a race condition.
The suggested solution is to confine your GUI to a single thread and communicate from your worker thread to the GUI thread to have it perform user interaction on the worker thread's behalf. The easiest way to accomplish this is to call SendMessage from the worker thread to block until the GUI thread's message handler returns. If the worker thread should continue to run while the dialog is displayed you could use PostMessage instead and communicate back to the worker thread using PostThreadMessage or signaling a synchronization object like an Event Object.
First of all, I'd like to agree with other posters that it's probably better to show the dialog on the main UI thread.
However, if you must, you can make a dialog on another thread modal with the following steps:
Pass your active window as an owner when creating the dialog.
When dialog is showing, iterate over your other windows and do them EnableWindow(FALSE). When the dialog is hiding, do the reverse. You will probably have to remember windows' enabled state and restore the original state, not just EnableWindow(TRUE).
Ensure that accelerators and other global commands will be ignored while the dialog is shown.
Note that (2) shouldn't be necessary provided that you do (1), but you've mentioned MFC, and I don't remember exactly how it behaves. It has it's own modal dialog implementation which may not exactly match Win32. If you're lucky, (1) and (3) will be enough.
While i don't know about the specifics of dialog handling on Server 2003, the simplest workaround to get on the main thread would be to use a custom window message, do ::SendMessage() and display the dialog in the message handler.
I recommend you not to do what the question subject suggests, and confine all UI to one thread. If you need the other thread to communicate with the user, create some messaging mechanism that will ask the UI thread to do it, and transport the results back.