Krita Source Code Documentation
Loading...
Searching...
No Matches
KisSynchronizedConnection< Args > Class Template Reference

#include <KisSynchronizedConnection.h>

+ Inheritance diagram for KisSynchronizedConnection< Args >:

Public Types

using ArgsTuple = std::tuple<Args...>
 
using CallbackFunction = std::function<void (Args...)>
 

Public Member Functions

template<typename Dptr , typename C , typename R , typename ... MemFnArgs>
void connectInputSignal (Dptr object, R(C::*memfn)(MemFnArgs...))
 
template<typename Dptr , typename C , typename R , typename ... MemFnArgs>
void connectOutputSlot (Dptr object, R(C::*memfn)(MemFnArgs...))
 
template<typename Dptr1 , typename C1 , typename R1 , typename ... MemFnArgs1, typename Dptr2 , typename C2 , typename R2 , typename ... MemFnArgs2>
void connectSync (Dptr1 object1, R1(C1::*memfn1)(MemFnArgs1...), Dptr2 object2, R2(C2::*memfn2)(MemFnArgs2...))
 
bool hasPendingSignals () const
 
 KisSynchronizedConnection ()=default
 
 KisSynchronizedConnection (CallbackFunction callback)
 
void setCallback (CallbackFunction callback)
 
void start (const Args &...argsTuple)
 

Protected Member Functions

void deliverEventToReceiver () override
 
- Protected Member Functions inherited from KisSynchronizedConnectionBase
bool event (QEvent *event) override
 
void postEvent ()
 

Private Member Functions

template<typename Dptr , typename C , typename R , typename ... MemFnArgs, std::size_t ... Idx>
CallbackFunction bindToMemberFunction (Dptr object, R(C::*memfn)(MemFnArgs...), std::index_sequence< Idx... >)
 

Private Attributes

CallbackFunction m_callback
 
QMutex m_inputConnectionMutex
 
std::queue< ArgsTuplem_queue
 

Additional Inherited Members

- Static Public Member Functions inherited from KisSynchronizedConnectionBase
static int eventType ()
 
static void forceDeliverAllSynchronizedEvents ()
 
static bool isAutoModeForUnittestsEnabled ()
 
static void registerSynchronizedEventBarrier (std::function< void()> callback)
 
static void setAutoModeForUnittestsEnabled (bool value)
 

Detailed Description

template<typename... Args>
class KisSynchronizedConnection< Args >

A "simple" class for ensuring a queued connection is never executed in a recursive event processing loop.

In several places in Krita we use queued signals for synchronizing image changes to the GUI. In such cases we use Qt::DirectConnection to fetch some data from the image, wrap that into the signal parameters and post at the events queue as a queued signal. Obviously, we expect this queued signal to be executed "after all the currently processed GUI actions are finished". But that is not always true in Qt...

In Qt the queued signal will be executed "as soon as execution path returns to the event loop". And it can also happen when a nested event loop started (by opening a QDialog) or QApplication::processEvent() is called. It means that the processing of a queued signal can start before the currently running GUI action is finished (because the current task has been recursively overridden by KisBusyWaitBroker.

KisSynchronizedConnection is workaround to this problem. Every connection made via KisSynchronizedConnection ensures that the target slot is executed without any recursion. The class tried to resemble new member-function-pointer-based API of QObject::connect.

In case the signal is emitted from the GUI thread, KisSynchronizedConnection behaves as Qt::AutoConnection, that is, delivers event right away, skipping the event loop.

Under the hood the class uses a custom event (KisSynchronizedConnectionEvent), which is recognized by KisApplication and postponed until the recursion state is over.

Parameters
Args...the list of arguments that are passed through the signal

Usage:

   \code{.cpp}

   class KisImage
   {
       // ...
   Q_SIGNALS:
       void sigRequestNodeReselection(KisNodeSP activeNode, const KisNodeList &selectedNodes);
   };

   KisSynchronizedConnection<KisNodeSP, KisNodeList> connection;

   // if you want connect input and output separately
   connection.connectInputSignal(image, &KisImage::sigRequestNodeReselection);
   connection.connectOutputSlot(nodeManager, &KisNodeManager::slotImageRequestNodeReselection)

   // if you want to connect them in one call (in QObject style)
   connection.connectSync(image, &KisImage::sigRequestNodeReselection,
                          nodeManager, &KisNodeManager::slotImageRequestNodeReselection);

   \endcode

Definition at line 131 of file KisSynchronizedConnection.h.

Member Typedef Documentation

◆ ArgsTuple

template<typename... Args>
using KisSynchronizedConnection< Args >::ArgsTuple = std::tuple<Args...>

Definition at line 135 of file KisSynchronizedConnection.h.

◆ CallbackFunction

template<typename... Args>
using KisSynchronizedConnection< Args >::CallbackFunction = std::function<void (Args...)>

Definition at line 136 of file KisSynchronizedConnection.h.

Constructor & Destructor Documentation

◆ KisSynchronizedConnection() [1/2]

template<typename... Args>
KisSynchronizedConnection< Args >::KisSynchronizedConnection ( )
default

◆ KisSynchronizedConnection() [2/2]

template<typename... Args>
KisSynchronizedConnection< Args >::KisSynchronizedConnection ( CallbackFunction callback)
inline

Definition at line 140 of file KisSynchronizedConnection.h.

141 : m_callback(callback)
142 {}

Member Function Documentation

◆ bindToMemberFunction()

template<typename... Args>
template<typename Dptr , typename C , typename R , typename ... MemFnArgs, std::size_t ... Idx>
CallbackFunction KisSynchronizedConnection< Args >::bindToMemberFunction ( Dptr object,
R(C::*)(MemFnArgs...) memfn,
std::index_sequence< Idx... >  )
inlineprivate

we cannot use std::bind here, because it doesn't support indexed iteration over the argument placeholders

Definition at line 216 of file KisSynchronizedConnection.h.

216 {
217
220
221 return boost::bind(memfn, object, boost::arg<Idx>()...);
222 }

◆ connectInputSignal()

template<typename... Args>
template<typename Dptr , typename C , typename R , typename ... MemFnArgs>
void KisSynchronizedConnection< Args >::connectInputSignal ( Dptr object,
R(C::*)(MemFnArgs...) memfn )
inline

Connect input signal to the connection

This part of the connection is based on Qt-signal mechanism, therefore object should be convertible into const QObject*.

Definition at line 170 of file KisSynchronizedConnection.h.

170 {
171 static_assert (std::is_convertible<Dptr, const C*>::value, "Source object should be convertible into the base of the member pointer");
172 static_assert (std::is_convertible<Dptr, const QObject*>::value, "Source object should be convertible into QObject");
173
174 QObject::connect(static_cast<const C*>(object), memfn,
175 this, &KisSynchronizedConnection::start, Qt::DirectConnection);
176 }
#define C(i, j)
void start(const Args &...argsTuple)

References C, and KisSynchronizedConnection< Args >::start().

◆ connectOutputSlot()

template<typename... Args>
template<typename Dptr , typename C , typename R , typename ... MemFnArgs>
void KisSynchronizedConnection< Args >::connectOutputSlot ( Dptr object,
R(C::*)(MemFnArgs...) memfn )
inline

Connect output slot to the connection

Since destination slot doesn't use Qt-signal machinery, the destination object shouldn't necessarily be a QObject. It should just be a member function with a compatible signature.

Definition at line 186 of file KisSynchronizedConnection.h.

186 {
187 static_assert (std::is_convertible<Dptr, C*>::value, "Destination object should be convertible into the base of the member pointer");
189
190 m_callback = bindToMemberFunction(object, memfn,
192 std::tuple_size<ArgsTuple>::value>());
193 }
CallbackFunction bindToMemberFunction(Dptr object, R(C::*memfn)(MemFnArgs...), std::index_sequence< Idx... >)
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
typename detail::make_index_sequence_from_1_impl< Num >::type make_index_sequence_from_1
Definition KisMpl.h:44

References KisSynchronizedConnection< Args >::bindToMemberFunction(), KIS_SAFE_ASSERT_RECOVER_RETURN, and KisSynchronizedConnection< Args >::m_callback.

◆ connectSync()

template<typename... Args>
template<typename Dptr1 , typename C1 , typename R1 , typename ... MemFnArgs1, typename Dptr2 , typename C2 , typename R2 , typename ... MemFnArgs2>
void KisSynchronizedConnection< Args >::connectSync ( Dptr1 object1,
R1(C1::*)(MemFnArgs1...) memfn1,
Dptr2 object2,
R2(C2::*)(MemFnArgs2...) memfn2 )
inline

A convenience method for setting up input and output connections at the same time

Definition at line 201 of file KisSynchronizedConnection.h.

202 {
203
204 connectInputSignal(object1, memfn1);
205 connectOutputSlot(object2, memfn2);
206 }
void connectInputSignal(Dptr object, R(C::*memfn)(MemFnArgs...))
void connectOutputSlot(Dptr object, R(C::*memfn)(MemFnArgs...))

References KisSynchronizedConnection< Args >::connectInputSignal(), and KisSynchronizedConnection< Args >::connectOutputSlot().

◆ deliverEventToReceiver()

template<typename... Args>
void KisSynchronizedConnection< Args >::deliverEventToReceiver ( )
inlineoverrideprotectedvirtual

Implements KisSynchronizedConnectionBase.

Definition at line 225 of file KisSynchronizedConnection.h.

225 {
226 ArgsTuple args;
227
228 {
229 QMutexLocker l(&m_inputConnectionMutex);
230 args = m_queue.front();
231 m_queue.pop();
232 }
233
234 std::apply(m_callback, args);
235 }

References KisSynchronizedConnection< Args >::m_callback, KisSynchronizedConnection< Args >::m_inputConnectionMutex, and KisSynchronizedConnection< Args >::m_queue.

◆ hasPendingSignals()

template<typename... Args>
bool KisSynchronizedConnection< Args >::hasPendingSignals ( ) const
inline

Definition at line 208 of file KisSynchronizedConnection.h.

208 {
209 QMutexLocker l(&m_inputConnectionMutex);
210 return !m_queue.empty();
211 }

References KisSynchronizedConnection< Args >::m_inputConnectionMutex, and KisSynchronizedConnection< Args >::m_queue.

◆ setCallback()

template<typename... Args>
void KisSynchronizedConnection< Args >::setCallback ( CallbackFunction callback)
inline

Sets an arbitrary callback as a destination slot in the connection. The callback should have a signature void (Args...)

Definition at line 159 of file KisSynchronizedConnection.h.

References KisSynchronizedConnection< Args >::m_callback.

◆ start()

template<typename... Args>
void KisSynchronizedConnection< Args >::start ( const Args &... argsTuple)
inline

Triggers the delivery of the signal to the destination slot manually

Definition at line 147 of file KisSynchronizedConnection.h.

147 {
148 {
149 QMutexLocker l(&m_inputConnectionMutex);
150 m_queue.emplace(std::make_tuple(argsTuple...));
151 }
152 this->postEvent();
153 }

References KisSynchronizedConnection< Args >::m_inputConnectionMutex, KisSynchronizedConnection< Args >::m_queue, and KisSynchronizedConnectionBase::postEvent().

Member Data Documentation

◆ m_callback

template<typename... Args>
CallbackFunction KisSynchronizedConnection< Args >::m_callback
private

Definition at line 238 of file KisSynchronizedConnection.h.

◆ m_inputConnectionMutex

template<typename... Args>
QMutex KisSynchronizedConnection< Args >::m_inputConnectionMutex
mutableprivate

Definition at line 240 of file KisSynchronizedConnection.h.

◆ m_queue

template<typename... Args>
std::queue<ArgsTuple> KisSynchronizedConnection< Args >::m_queue
private

Definition at line 239 of file KisSynchronizedConnection.h.


The documentation for this class was generated from the following file: