less connections in QskControl::QskControl

This commit is contained in:
Uwe Rathmann 2017-12-14 09:41:10 +01:00
parent 154bae4dac
commit d63fae938d
3 changed files with 129 additions and 54 deletions

View File

@ -7,6 +7,7 @@
#include "QskAspect.h" #include "QskAspect.h"
#include "QskSetup.h" #include "QskSetup.h"
#include "QskSkinlet.h" #include "QskSkinlet.h"
#include "QskSkin.h"
#include "QskEvent.h" #include "QskEvent.h"
#include "QskDirtyItemFilter.h" #include "QskDirtyItemFilter.h"
#include "QskSkinHintTable.h" #include "QskSkinHintTable.h"
@ -23,6 +24,7 @@ QSK_QT_PRIVATE_BEGIN
QSK_QT_PRIVATE_END QSK_QT_PRIVATE_END
#include <limits> #include <limits>
#include <unordered_set>
#include <unordered_map> #include <unordered_map>
QSK_STATE( QskControl, Disabled, QskAspect::FirstSystemState ) QSK_STATE( QskControl, Disabled, QskAspect::FirstSystemState )
@ -31,7 +33,8 @@ QSK_STATE( QskControl, Focused, QskAspect::LastSystemState )
typedef quint16 controlFlags_t; typedef quint16 controlFlags_t;
void qskResolveLocale( QskControl* ); void qskResolveLocale( QskControl* ); // not static as being used from outside !
static void qskUpdateControlFlags( QskControl::Flags, QskControl* );
static inline void qskSendEventTo( QObject* object, QEvent::Type type ) static inline void qskSendEventTo( QObject* object, QEvent::Type type )
{ {
@ -98,9 +101,59 @@ namespace
int m_refCount; int m_refCount;
QQuickWindow* m_window; QQuickWindow* m_window;
}; };
class QskControlRegistry
{
public:
QskControlRegistry()
{
/*
Its faster and saves some memory to have this registry instead
of setting up direct connections between qskSetup and each control
*/
QObject::connect( qskSetup, &QskSetup::controlFlagsChanged,
[this] { updateControlFlags(); } );
QObject::connect( qskSetup, &QskSetup::skinChanged,
[this] { updateSkin(); } );
}
inline void insert( QskControl* control )
{
m_controls.insert( control );
}
inline void remove( QskControl* control )
{
m_controls.erase( control );
}
void updateControlFlags()
{
const auto flags = static_cast< QskControl::Flags >( qskControlFlags() );
for ( auto control : m_controls )
qskUpdateControlFlags( flags, control );
}
void updateSkin()
{
QEvent event( QEvent::StyleChange );
for ( auto control : m_controls )
{
event.setAccepted( true );
QCoreApplication::sendEvent( control, &event );
}
}
private:
std::unordered_set< QskControl* > m_controls;
};
} }
Q_GLOBAL_STATIC( QskWindowStore, qskReleasedWindowCounter ) Q_GLOBAL_STATIC( QskWindowStore, qskReleasedWindowCounter )
Q_GLOBAL_STATIC( QskControlRegistry, qskRegistry )
class QskControlPrivate final : public QQuickItemPrivate class QskControlPrivate final : public QQuickItemPrivate
{ {
@ -219,6 +272,28 @@ public:
return q->gestureFilter( child, event ); return q->gestureFilter( child, event );
} }
void updateControlFlags( QskControl::Flags flags )
{
Q_Q( QskControl );
const auto oldFlags = controlFlags;
const auto newFlags = static_cast< controlFlags_t >( flags );
if ( oldFlags != newFlags )
{
const auto numBits = qCountTrailingZeroBits(
static_cast< quint32 >( QskControl::LastFlag ) );
for ( quint32 i = 0; i <= numBits; ++i )
{
const quint32 flag = ( 1 << i );
q->updateControlFlag( flag, flags & flag );
}
Q_EMIT q->controlFlagsChanged();
}
}
QLocale locale; QLocale locale;
quint16 controlFlags; quint16 controlFlags;
@ -254,27 +329,34 @@ QskControl::QskControl( QQuickItem* parent ):
qskResolveLocale( this ); qskResolveLocale( this );
} }
// since Qt 5.10 we have QQuickItem::ItemEnabledHasChanged
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
/*
Setting up this connections slows down the time needed
for construction by almost 100%. Would be nice to
avoid this penalty also for earlier Qt versions.
*/
connect( this, &QQuickItem::enabledChanged, connect( this, &QQuickItem::enabledChanged,
[this] { setSkinStateFlag( Disabled, !isEnabled() ); } ); [this] { setSkinStateFlag( Disabled, !isEnabled() ); } );
#endif #endif
#if 1
/*
Would be good to get rid of this connection as it slows down
the constructor by ~25% ( when ignoring the locale )
*/
connect( qskSetup, &QskSetup::controlFlagsChanged,
this, [this] { updateControlFlags( static_cast< Flags >( qskControlFlags() ) ); } );
#endif
Q_D( QskControl ); Q_D( QskControl );
if ( d->controlFlags & QskControl::DeferredUpdate ) if ( d->controlFlags & QskControl::DeferredUpdate )
qskFilterWindow( window() ); qskFilterWindow( window() );
qskRegistry->insert( this );
}
static void qskUpdateControlFlags( QskControl::Flags flags, QskControl* control )
{
auto d = static_cast< QskControlPrivate* >( QQuickItemPrivate::get( control ) );
d->updateControlFlags( flags );
} }
QskControl::~QskControl() QskControl::~QskControl()
{ {
if ( qskRegistry )
qskRegistry->remove( this );
} }
const char* QskControl::className() const const char* QskControl::className() const
@ -506,16 +588,20 @@ QskControl::Flags QskControl::controlFlags() const
void QskControl::setControlFlags( Flags flags ) void QskControl::setControlFlags( Flags flags )
{ {
Q_D( QskControl );
// set all bits in the mask // set all bits in the mask
d_func()->controlFlagsMask = std::numeric_limits< controlFlags_t >::max(); d->controlFlagsMask = std::numeric_limits< controlFlags_t >::max();
updateControlFlags( flags ); d->updateControlFlags( flags );
} }
void QskControl::resetControlFlags() void QskControl::resetControlFlags()
{ {
Q_D( QskControl );
// clear all bits in the mask // clear all bits in the mask
d_func()->controlFlagsMask = 0; d->controlFlagsMask = 0;
updateControlFlags( static_cast< Flags >( qskControlFlags() ) ); d->updateControlFlags( static_cast< Flags >( qskControlFlags() ) );
} }
void QskControl::setControlFlag( Flag flag, bool on ) void QskControl::setControlFlag( Flag flag, bool on )
@ -551,26 +637,6 @@ bool QskControl::testControlFlag( Flag flag ) const
return d_func()->controlFlags & flag; return d_func()->controlFlags & flag;
} }
void QskControl::updateControlFlags( Flags flags )
{
const auto oldFlags = d_func()->controlFlags;
const auto newFlags = static_cast< controlFlags_t >( flags );
if ( oldFlags != newFlags )
{
const auto numBits = qCountTrailingZeroBits(
static_cast< quint32 >( LastFlag ) );
for ( quint32 i = 0; i <= numBits; ++i )
{
const quint32 flag = ( 1 << i );
updateControlFlag( flag, flags & flag );
}
Q_EMIT controlFlagsChanged();
}
}
void QskControl::updateControlFlag( uint flag, bool on ) void QskControl::updateControlFlag( uint flag, bool on )
{ {
Q_D( QskControl ); Q_D( QskControl );
@ -954,13 +1020,40 @@ bool QskControl::event( QEvent* event )
switch( eventType ) switch( eventType )
{ {
case QEvent::StyleChange:
{
// The skin has changed
if ( skinlet() == nullptr )
{
/*
When we don't have a local skinlet, the skinlet
from the previous skin might be cached.
*/
setSkinlet( nullptr );
}
/*
We might have a totally different skinlet,
that can't deal with nodes created from other skinlets
*/
d_func()->clearPreviousNodes = true;
resetImplicitSize();
polish();
update();
changeEvent( event );
return true;
}
case QEvent::EnabledChange: case QEvent::EnabledChange:
case QEvent::FontChange: case QEvent::FontChange:
case QEvent::PaletteChange: case QEvent::PaletteChange:
case QEvent::LocaleChange: case QEvent::LocaleChange:
case QEvent::ReadOnlyChange: case QEvent::ReadOnlyChange:
case QEvent::ParentChange: case QEvent::ParentChange:
case QEvent::StyleChange:
case QEvent::ContentsRectChange: case QEvent::ContentsRectChange:
{ {
changeEvent( event ); changeEvent( event );
@ -1175,7 +1268,7 @@ void QskControl::itemChange( QQuickItem::ItemChange change,
break; break;
} }
#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)
case QQuickItem::QQuickItem::ItemEnabledHasChanged: case QQuickItem::ItemEnabledHasChanged:
{ {
setSkinStateFlag( Disabled, !value.boolValue ); setSkinStateFlag( Disabled, !value.boolValue );
break; break;

View File

@ -222,7 +222,6 @@ private:
void updateImplicitSize(); void updateImplicitSize();
void updateControlFlag( uint flag, bool on ); void updateControlFlag( uint flag, bool on );
void updateControlFlags( Flags );
private: private:
Q_DECLARE_PRIVATE( QskControl ) Q_DECLARE_PRIVATE( QskControl )

View File

@ -21,9 +21,6 @@
#include <QElapsedTimer> #include <QElapsedTimer>
#include <QMarginsF> #include <QMarginsF>
#include <unordered_map>
#include <set>
#define DEBUG_MAP 0 #define DEBUG_MAP 0
#define DEBUG_ANIMATOR 0 #define DEBUG_ANIMATOR 0
#define DEBUG_STATE 0 #define DEBUG_STATE 0
@ -129,7 +126,6 @@ public:
const QskSkinlet* skinlet; const QskSkinlet* skinlet;
QMetaObject::Connection connection;
QskAspect::State skinState; QskAspect::State skinState;
bool hasLocalSkinlet : 1; bool hasLocalSkinlet : 1;
}; };
@ -137,23 +133,10 @@ public:
QskSkinnable::QskSkinnable(): QskSkinnable::QskSkinnable():
m_data( new PrivateData() ) m_data( new PrivateData() )
{ {
auto skinChangedHandler =
[ this ]( QskSkin* )
{
if ( !m_data->hasLocalSkinlet )
setSkinlet( nullptr );
QEvent event( QEvent::StyleChange );
QCoreApplication::sendEvent( owningControl(), &event );
};
m_data->connection = QObject::connect(
qskSetup, &QskSetup::skinChanged, skinChangedHandler );
} }
QskSkinnable::~QskSkinnable() QskSkinnable::~QskSkinnable()
{ {
QObject::disconnect( m_data->connection );
} }
void QskSkinnable::setSkinlet( const QskSkinlet* skinlet ) void QskSkinnable::setSkinlet( const QskSkinlet* skinlet )