2017-07-21 18:21:34 +02:00
|
|
|
/******************************************************************************
|
|
|
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
|
|
|
* This file may be used under the terms of the QSkinny License, Version 1.0
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
#include "QskWindow.h"
|
|
|
|
#include "QskControl.h"
|
2018-08-03 08:15:28 +02:00
|
|
|
#include "QskEvent.h"
|
2018-05-01 12:41:20 +02:00
|
|
|
#include "QskQuick.h"
|
2017-07-21 18:21:34 +02:00
|
|
|
#include "QskSetup.h"
|
|
|
|
|
2018-07-19 14:10:48 +02:00
|
|
|
#include <qmath.h>
|
|
|
|
#include <qpointer.h>
|
2017-07-21 18:21:34 +02:00
|
|
|
|
|
|
|
QSK_QT_PRIVATE_BEGIN
|
|
|
|
#include <private/qquickitem_p.h>
|
|
|
|
#include <private/qquickitemchangelistener_p.h>
|
|
|
|
#include <private/qquickwindow_p.h>
|
|
|
|
#include <private/qsgrenderer_p.h>
|
|
|
|
QSK_QT_PRIVATE_END
|
|
|
|
|
2020-03-10 10:21:59 +01:00
|
|
|
#include <qpa/qwindowsysteminterface.h>
|
|
|
|
#include <QGuiApplication>
|
|
|
|
|
2020-03-10 10:42:24 +01:00
|
|
|
// #define QSK_DEBUG_RENDER_TIMING
|
2020-03-10 10:21:59 +01:00
|
|
|
|
|
|
|
#ifdef QSK_DEBUG_RENDER_TIMING
|
|
|
|
|
2020-03-12 11:26:14 +01:00
|
|
|
// does not work with Qt >= 5.12 TODO ...
|
|
|
|
|
2020-03-10 10:21:59 +01:00
|
|
|
#include <qelapsedtimer.h>
|
|
|
|
#include <qloggingcategory.h>
|
|
|
|
Q_LOGGING_CATEGORY( logTiming, "qsk.window.timing", QtCriticalMsg )
|
2020-08-09 11:50:34 +02:00
|
|
|
|
2020-03-12 11:17:43 +01:00
|
|
|
#if QT_VERSION >= QT_VERSION_CHECK( 5, 12, 0 )
|
|
|
|
QSK_QT_PRIVATE_BEGIN
|
|
|
|
#include <qpa/qplatformwindow_p.h>
|
|
|
|
QSK_QT_PRIVATE_END
|
|
|
|
#endif
|
|
|
|
|
2020-03-10 10:21:59 +01:00
|
|
|
#endif
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
static void qskResolveLocale( QskWindow* );
|
|
|
|
static bool qskEnforcedSkin = false;
|
|
|
|
|
2018-01-24 10:14:50 +01:00
|
|
|
static inline void qskSendEventTo( QObject* object, QEvent::Type type )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
QEvent event( type );
|
|
|
|
QCoreApplication::sendEvent( object, &event );
|
|
|
|
}
|
|
|
|
|
2018-01-24 10:14:50 +01:00
|
|
|
static QQuickItem* qskDefaultFocusItem( QQuickWindow* window )
|
|
|
|
{
|
|
|
|
const auto children = qskPaintOrderChildItems( window->contentItem() );
|
2018-08-03 08:15:28 +02:00
|
|
|
for ( auto it = children.crbegin(); it != children.crend(); ++it )
|
2018-01-24 10:14:50 +01:00
|
|
|
{
|
|
|
|
auto child = *it;
|
|
|
|
|
|
|
|
if ( child->isFocusScope() && child->isVisible()
|
|
|
|
&& child->isEnabled() && child->activeFocusOnTab() )
|
|
|
|
{
|
|
|
|
return child;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return window->contentItem()->nextItemInFocusChain( true );
|
|
|
|
}
|
|
|
|
|
2020-03-12 11:17:43 +01:00
|
|
|
#ifdef QSK_DEBUG_RENDER_TIMING
|
|
|
|
static inline int qskUpdateTimerId( const QWindow* window )
|
|
|
|
{
|
|
|
|
#if QT_VERSION >= QT_VERSION_CHECK( 5, 12, 0 )
|
|
|
|
class PlatformWindow : public QPlatformWindow
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
int updateTimerId() const
|
|
|
|
{
|
|
|
|
return d_ptr->updateTimer.timerId();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
auto platformWindow = static_cast< const PlatformWindow* >( window->handle() );
|
|
|
|
return platformWindow->updateTimerId();
|
|
|
|
#else
|
|
|
|
auto w = const_cast< QWindow* >( window );
|
|
|
|
return QWindowPrivate::get( w )->updateTimer;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
namespace
|
|
|
|
{
|
|
|
|
class ChildListener final : public QQuickItemChangeListener
|
|
|
|
{
|
2018-08-03 08:15:28 +02:00
|
|
|
public:
|
2018-10-05 14:15:17 +02:00
|
|
|
void setEnabled( QQuickItem* contentItem, bool on )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2018-10-05 14:15:17 +02:00
|
|
|
m_contentItem = contentItem;
|
2017-07-21 18:21:34 +02:00
|
|
|
|
|
|
|
const QQuickItemPrivate::ChangeTypes types = QQuickItemPrivate::Children;
|
|
|
|
|
2018-10-05 14:15:17 +02:00
|
|
|
QQuickItemPrivate* p = QQuickItemPrivate::get( contentItem );
|
2017-07-21 18:21:34 +02:00
|
|
|
if ( on )
|
|
|
|
p->addItemChangeListener( this, types );
|
|
|
|
else
|
|
|
|
p->removeItemChangeListener( this, types );
|
|
|
|
}
|
|
|
|
|
2018-07-31 17:32:25 +02:00
|
|
|
void itemChildAdded( QQuickItem*, QQuickItem* ) override
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2018-10-05 14:15:17 +02:00
|
|
|
QskWindow* window = static_cast< QskWindow* >( m_contentItem->window() );
|
2017-07-21 18:21:34 +02:00
|
|
|
if ( window->isExposed() )
|
|
|
|
{
|
2018-10-05 14:15:17 +02:00
|
|
|
// the child is not fully constructed
|
2017-07-21 18:21:34 +02:00
|
|
|
QCoreApplication::postEvent( window, new QEvent( QEvent::LayoutRequest ) );
|
|
|
|
}
|
|
|
|
}
|
2018-03-24 18:05:57 +01:00
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
private:
|
2019-06-19 13:24:53 +02:00
|
|
|
QQuickItem* m_contentItem = nullptr;
|
2017-07-21 18:21:34 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int qskToIntegerConstraint( qreal valueF )
|
|
|
|
{
|
|
|
|
int value = -1;
|
|
|
|
|
|
|
|
if ( valueF >= 0.0 )
|
|
|
|
{
|
|
|
|
if ( valueF >= std::numeric_limits< int >::max() )
|
|
|
|
value = std::numeric_limits< int >::max();
|
|
|
|
else
|
2018-08-03 08:15:28 +02:00
|
|
|
value = ( int ) qCeil( valueF );
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
class QskWindowPrivate : public QQuickWindowPrivate
|
|
|
|
{
|
|
|
|
Q_DECLARE_PUBLIC( QskWindow )
|
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
public:
|
|
|
|
QskWindowPrivate()
|
|
|
|
: preferredSize( -1, -1 )
|
|
|
|
, eventAcceptance( QskWindow::EventProcessed )
|
|
|
|
, explicitLocale( false )
|
|
|
|
, deleteOnClose( false )
|
|
|
|
, autoLayoutChildren( true )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2020-03-10 10:21:59 +01:00
|
|
|
#ifdef QSK_DEBUG_RENDER_TIMING
|
|
|
|
QElapsedTimer renderInterval;
|
|
|
|
#endif
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
ChildListener contentItemListener;
|
|
|
|
QLocale locale;
|
|
|
|
|
|
|
|
// minimum/maximum constraints are offered by QWindow
|
|
|
|
QSize preferredSize;
|
|
|
|
|
2018-06-25 12:36:15 +02:00
|
|
|
QskWindow::EventAcceptance eventAcceptance;
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
bool explicitLocale : 1;
|
|
|
|
bool deleteOnClose : 1;
|
|
|
|
bool autoLayoutChildren : 1;
|
|
|
|
};
|
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
QskWindow::QskWindow( QWindow* parent )
|
|
|
|
: Inherited( *( new QskWindowPrivate() ), parent )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
QSurfaceFormat fmt = format();
|
|
|
|
fmt.setSamples( 4 );
|
|
|
|
setFormat( fmt );
|
|
|
|
|
2019-01-21 15:21:42 +01:00
|
|
|
/*
|
|
|
|
So that inheriting/resolving of the locale works
|
|
|
|
over all windows and items.
|
|
|
|
*/
|
|
|
|
contentItem()->setProperty( "locale", locale() );
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
if ( parent )
|
|
|
|
{
|
|
|
|
// also when the parent changes TODO ...
|
|
|
|
qskResolveLocale( this );
|
|
|
|
}
|
|
|
|
|
|
|
|
d_func()->contentItemListener.setEnabled( contentItem(), true );
|
|
|
|
|
|
|
|
if ( !qskEnforcedSkin )
|
|
|
|
connect( this, &QQuickWindow::afterAnimating, this, &QskWindow::enforceSkin );
|
|
|
|
}
|
|
|
|
|
2020-03-12 09:58:40 +01:00
|
|
|
QskWindow::QskWindow( QQuickRenderControl* renderControl, QWindow* parent )
|
2020-03-10 10:21:59 +01:00
|
|
|
: QskWindow( parent )
|
|
|
|
{
|
2020-05-10 11:16:39 +02:00
|
|
|
Q_D( QskWindow );
|
|
|
|
|
2020-03-10 10:21:59 +01:00
|
|
|
d->renderControl = renderControl;
|
|
|
|
d->init( this, renderControl );
|
|
|
|
}
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
QskWindow::~QskWindow()
|
|
|
|
{
|
2020-05-10 11:16:39 +02:00
|
|
|
#if QT_VERSION < QT_VERSION_CHECK( 5, 12, 0 )
|
2017-07-21 18:21:34 +02:00
|
|
|
// When being used from Qml the item destruction would run in the most
|
|
|
|
// unefficient way, leading to lots of QQuickItem::ItemChildRemovedChange
|
2020-05-10 11:16:39 +02:00
|
|
|
// depending operations.
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2020-05-24 10:07:35 +02:00
|
|
|
QVector< QPointer< QQuickItem > > items;
|
|
|
|
|
|
|
|
const auto children = contentItem()->childItems();
|
|
|
|
for ( auto child : children )
|
|
|
|
{
|
|
|
|
if ( child->parent() == contentItem() )
|
|
|
|
items += child;
|
|
|
|
}
|
2017-10-30 14:38:30 +01:00
|
|
|
|
2020-05-24 10:07:35 +02:00
|
|
|
for ( auto& item : qskAsConst( items ) )
|
|
|
|
delete item;
|
2020-05-10 11:16:39 +02:00
|
|
|
#endif
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
2020-03-10 10:21:59 +01:00
|
|
|
void QskWindow::setScreen( const QString& name )
|
|
|
|
{
|
|
|
|
if ( !name.isEmpty() )
|
|
|
|
{
|
|
|
|
for ( auto screen : QGuiApplication::screens() )
|
|
|
|
{
|
|
|
|
if ( screen->name() == name )
|
|
|
|
{
|
|
|
|
setScreen( screen );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
setScreen( QGuiApplication::primaryScreen() );
|
|
|
|
}
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
void QskWindow::resizeF( const QSizeF& size )
|
|
|
|
{
|
|
|
|
const int w = static_cast< int >( qCeil( size.width() ) );
|
|
|
|
const int h = static_cast< int >( qCeil( size.height() ) );
|
|
|
|
|
|
|
|
resize( w, h );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool QskWindow::deleteOnClose() const
|
|
|
|
{
|
|
|
|
Q_D( const QskWindow );
|
|
|
|
return d->deleteOnClose;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskWindow::setDeleteOnClose( bool on )
|
|
|
|
{
|
|
|
|
Q_D( QskWindow );
|
2017-10-30 14:38:30 +01:00
|
|
|
|
|
|
|
if ( on != d->deleteOnClose )
|
|
|
|
{
|
|
|
|
d->deleteOnClose = on;
|
|
|
|
Q_EMIT deleteOnCloseChanged();
|
|
|
|
}
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void QskWindow::setAutoLayoutChildren( bool on )
|
|
|
|
{
|
|
|
|
Q_D( QskWindow );
|
|
|
|
|
|
|
|
if ( on != d->autoLayoutChildren )
|
|
|
|
{
|
|
|
|
d->autoLayoutChildren = on;
|
|
|
|
if ( on )
|
|
|
|
qskSendEventTo( this, QEvent::LayoutRequest );
|
|
|
|
|
|
|
|
Q_EMIT autoLayoutChildrenChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool QskWindow::autoLayoutChildren() const
|
|
|
|
{
|
|
|
|
Q_D( const QskWindow );
|
|
|
|
return d->autoLayoutChildren;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskWindow::addItem( QQuickItem* item )
|
|
|
|
{
|
|
|
|
if ( item == nullptr )
|
|
|
|
return;
|
|
|
|
|
|
|
|
item->setParent( contentItem() );
|
|
|
|
item->setParentItem( contentItem() );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskWindow::polishItems()
|
|
|
|
{
|
|
|
|
Q_D( QskWindow );
|
|
|
|
d->polishItems();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool QskWindow::event( QEvent* event )
|
|
|
|
{
|
2018-06-25 12:36:15 +02:00
|
|
|
/*
|
|
|
|
Qt/Quick is lacking a flag like Qt::WA_NoMousePropagation, so
|
|
|
|
the only way to stop propagating of input events is to accept
|
|
|
|
the event. Then the window can't decide anymore if someone was
|
|
|
|
interested and when to do some fallback handling.
|
|
|
|
To improve the situation we add an extra flag in QskWindow,
|
|
|
|
while the right class to solve this shortcoming would be QQuickWindow.
|
2018-08-03 08:15:28 +02:00
|
|
|
*/
|
2018-06-25 12:36:15 +02:00
|
|
|
|
|
|
|
Q_D( QskWindow );
|
|
|
|
d->eventAcceptance = EventProcessed;
|
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
switch ( event->type() )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
case QEvent::Show:
|
|
|
|
{
|
|
|
|
if ( size().isEmpty() )
|
|
|
|
{
|
2019-09-18 09:12:39 +02:00
|
|
|
QSize sz = sizeConstraint();
|
2017-07-21 18:21:34 +02:00
|
|
|
if ( !sz.isEmpty() )
|
2019-06-19 13:24:53 +02:00
|
|
|
{
|
|
|
|
sz = sz.expandedTo( minimumSize() );
|
|
|
|
sz = sz.boundedTo( maximumSize() );
|
|
|
|
|
2019-06-14 13:00:28 +02:00
|
|
|
resize( sz );
|
2019-06-19 13:24:53 +02:00
|
|
|
}
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case QEvent::LayoutRequest:
|
|
|
|
{
|
|
|
|
if ( isExposed() )
|
|
|
|
layoutItems();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case QEvent::LocaleChange:
|
|
|
|
{
|
|
|
|
Q_EMIT localeChanged( locale() );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case QEvent::Close:
|
|
|
|
{
|
|
|
|
if ( event->isAccepted() )
|
|
|
|
{
|
|
|
|
if ( d->deleteOnClose )
|
|
|
|
deleteLater();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2020-03-10 10:21:59 +01:00
|
|
|
#ifdef QSK_DEBUG_RENDER_TIMING
|
|
|
|
case QEvent::Timer:
|
|
|
|
{
|
|
|
|
if ( logTiming().isDebugEnabled() )
|
|
|
|
{
|
2020-03-12 11:17:43 +01:00
|
|
|
const int updateTimerId = qskUpdateTimerId( this );
|
|
|
|
|
2020-08-09 11:50:34 +02:00
|
|
|
if ( static_cast< QTimerEvent* >( event )->timerId() == updateTimerId )
|
2020-03-10 10:21:59 +01:00
|
|
|
{
|
|
|
|
if ( !d->renderInterval.isValid() )
|
|
|
|
d->renderInterval.start();
|
|
|
|
|
|
|
|
qCDebug( logTiming() ) << "update timer - elapsed"
|
|
|
|
<< d->renderInterval.restart() << this;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Inherited::event( event );
|
|
|
|
}
|
|
|
|
|
2018-01-24 10:14:50 +01:00
|
|
|
void QskWindow::keyPressEvent( QKeyEvent* event )
|
|
|
|
{
|
2020-07-27 18:03:02 +02:00
|
|
|
if ( qskFocusChainIncrement( event ) != 0 )
|
2018-01-24 10:14:50 +01:00
|
|
|
{
|
2018-02-06 14:57:34 +01:00
|
|
|
auto focusItem = activeFocusItem();
|
|
|
|
if ( focusItem == nullptr || focusItem == contentItem() )
|
2018-01-24 10:14:50 +01:00
|
|
|
{
|
2018-02-06 14:57:34 +01:00
|
|
|
/*
|
|
|
|
The Qt/Quick implementation for navigating along the
|
|
|
|
focus tab chain gives unsufficient results, when the
|
|
|
|
starting point is the root item. In this specific
|
|
|
|
situation we also have to include all items being
|
|
|
|
tab fences into consideration.
|
|
|
|
|
|
|
|
In certain situations Qt/Quick gets even stuck in a non
|
|
|
|
terminating loop: see Qt-Bug 65943
|
|
|
|
|
|
|
|
So we better block the focus navigation and find the
|
|
|
|
next focus item on our own.
|
|
|
|
*/
|
|
|
|
ensureFocus( Qt::TabFocusReason );
|
|
|
|
event->accept();
|
|
|
|
|
|
|
|
return;
|
2018-01-24 10:14:50 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Inherited::keyPressEvent( event );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskWindow::keyReleaseEvent( QKeyEvent* event )
|
|
|
|
{
|
|
|
|
Inherited::keyReleaseEvent( event );
|
|
|
|
}
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
void QskWindow::exposeEvent( QExposeEvent* event )
|
|
|
|
{
|
2018-01-24 10:14:50 +01:00
|
|
|
ensureFocus( Qt::OtherFocusReason );
|
2017-07-21 18:21:34 +02:00
|
|
|
layoutItems();
|
2018-01-24 10:14:50 +01:00
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
Inherited::exposeEvent( event );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskWindow::resizeEvent( QResizeEvent* event )
|
|
|
|
{
|
|
|
|
Inherited::resizeEvent( event );
|
|
|
|
|
|
|
|
if ( isExposed() )
|
|
|
|
layoutItems();
|
|
|
|
}
|
|
|
|
|
|
|
|
QLocale QskWindow::locale() const
|
|
|
|
{
|
|
|
|
Q_D( const QskWindow );
|
|
|
|
return d->locale;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskWindow::setLocale( const QLocale& locale )
|
|
|
|
{
|
|
|
|
Q_D( QskWindow );
|
|
|
|
|
|
|
|
d->explicitLocale = true;
|
|
|
|
|
|
|
|
if ( d->locale != locale )
|
|
|
|
{
|
|
|
|
d->locale = locale;
|
|
|
|
qskSendEventTo( this, QEvent::LocaleChange );
|
|
|
|
qskSetup->inheritLocale( this, locale );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskWindow::resetLocale()
|
|
|
|
{
|
|
|
|
Q_D( QskWindow );
|
|
|
|
|
|
|
|
d->explicitLocale = false;
|
|
|
|
qskResolveLocale( this );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool qskInheritLocale( QskWindow* window, const QLocale& locale )
|
|
|
|
{
|
|
|
|
auto d = static_cast< QskWindowPrivate* >( QQuickWindowPrivate::get( window ) );
|
|
|
|
|
|
|
|
if ( d->explicitLocale || d->locale == locale )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
d->locale = locale;
|
|
|
|
qskSendEventTo( window, QEvent::LocaleChange );
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void qskResolveLocale( QskWindow* window )
|
|
|
|
{
|
|
|
|
auto d = static_cast< QskWindowPrivate* >( QQuickWindowPrivate::get( window ) );
|
|
|
|
|
|
|
|
const QLocale locale = qskSetup->inheritedLocale( window );
|
|
|
|
|
|
|
|
if ( d->locale != locale )
|
|
|
|
{
|
|
|
|
d->locale = locale;
|
|
|
|
qskSendEventTo( window, QEvent::LocaleChange );
|
|
|
|
|
|
|
|
qskSetup->inheritLocale( window, locale );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskWindow::setPreferredSize( const QSize& size )
|
|
|
|
{
|
|
|
|
Q_D( QskWindow );
|
|
|
|
d->preferredSize = size;
|
|
|
|
}
|
|
|
|
|
|
|
|
QSize QskWindow::preferredSize() const
|
|
|
|
{
|
|
|
|
Q_D( const QskWindow );
|
|
|
|
return d->preferredSize;
|
|
|
|
}
|
|
|
|
|
2019-09-18 09:12:39 +02:00
|
|
|
QSize QskWindow::sizeConstraint() const
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
Q_D( const QskWindow );
|
|
|
|
|
|
|
|
QSizeF constraint = d->preferredSize;
|
|
|
|
|
|
|
|
if ( !constraint.isValid() )
|
|
|
|
{
|
|
|
|
const bool doWidth = constraint.width() < 0;
|
|
|
|
const bool doHeight = constraint.height() < 0;
|
|
|
|
|
2019-04-26 11:56:09 +02:00
|
|
|
const auto children = contentItem()->childItems();
|
2017-07-21 18:21:34 +02:00
|
|
|
for ( auto child : children )
|
|
|
|
{
|
2019-04-26 11:56:09 +02:00
|
|
|
if ( auto control = qskControlCast( child ) )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2019-09-18 09:12:39 +02:00
|
|
|
const QSizeF itemConstraint = control->sizeConstraint();
|
2019-06-19 13:24:53 +02:00
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
if ( doWidth )
|
|
|
|
constraint.setWidth( qMax( constraint.width(), itemConstraint.width() ) );
|
|
|
|
|
|
|
|
if ( doHeight )
|
|
|
|
constraint.setHeight( qMax( constraint.height(), itemConstraint.height() ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// QWindow geometries are in integers
|
|
|
|
|
|
|
|
return QSize( qskToIntegerConstraint( constraint.width() ),
|
|
|
|
qskToIntegerConstraint( constraint.height() ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskWindow::setFixedSize( const QSize& size )
|
|
|
|
{
|
|
|
|
// ????
|
|
|
|
setMinimumSize( size );
|
|
|
|
setMaximumSize( size );
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskWindow::layoutItems()
|
|
|
|
{
|
|
|
|
Q_D( QskWindow );
|
|
|
|
|
|
|
|
if ( !d->autoLayoutChildren )
|
|
|
|
return;
|
|
|
|
|
2018-03-24 18:05:57 +01:00
|
|
|
const QRectF rect = qskItemGeometry( contentItem() );
|
2017-07-21 18:21:34 +02:00
|
|
|
|
2017-10-30 14:38:30 +01:00
|
|
|
const auto children = contentItem()->childItems();
|
|
|
|
for ( auto child : children )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
2018-01-19 10:07:05 +01:00
|
|
|
if ( !qskIsTransparentForPositioner( child ) )
|
2019-09-16 12:30:00 +02:00
|
|
|
{
|
|
|
|
const auto r = qskConstrainedItemRect( child, rect );
|
|
|
|
qskSetItemGeometry( child, r );
|
|
|
|
}
|
2017-07-21 18:21:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-24 10:14:50 +01:00
|
|
|
void QskWindow::ensureFocus( Qt::FocusReason reason )
|
|
|
|
{
|
|
|
|
auto focusItem = contentItem()->scopedFocusItem();
|
|
|
|
|
|
|
|
if ( focusItem == nullptr )
|
|
|
|
{
|
|
|
|
focusItem = qskDefaultFocusItem( this );
|
|
|
|
if ( focusItem )
|
|
|
|
focusItem->setFocus( true, reason );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
void QskWindow::setCustomRenderMode( const char* mode )
|
|
|
|
{
|
|
|
|
class RenderJob final : public QRunnable
|
|
|
|
{
|
2018-08-03 08:15:28 +02:00
|
|
|
public:
|
|
|
|
RenderJob( QQuickWindow* window, const QByteArray mode )
|
|
|
|
: m_window( window )
|
|
|
|
, m_mode( mode )
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2018-07-31 17:32:25 +02:00
|
|
|
void run() override
|
2017-07-21 18:21:34 +02:00
|
|
|
{
|
|
|
|
auto* d = QQuickWindowPrivate::get( m_window );
|
|
|
|
|
|
|
|
d->customRenderMode = m_mode;
|
|
|
|
|
|
|
|
if ( d->renderer )
|
|
|
|
{
|
|
|
|
delete d->renderer->rootNode();
|
|
|
|
delete d->renderer;
|
|
|
|
d->renderer = nullptr;
|
|
|
|
|
|
|
|
QMetaObject::invokeMethod( m_window, "update" );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
private:
|
2017-07-21 18:21:34 +02:00
|
|
|
QQuickWindow* m_window;
|
|
|
|
const QByteArray m_mode;
|
|
|
|
};
|
|
|
|
|
|
|
|
const QByteArray m( mode );
|
|
|
|
|
|
|
|
Q_D( QskWindow );
|
|
|
|
if ( m != d->customRenderMode )
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
batch renderer uses an optimized memory allocation strategy,
|
|
|
|
that is disabled, when a customRenderMode is enabled.
|
|
|
|
This seems to be the reason for crashes, when changing the mode
|
|
|
|
at runtime. The code above tries to get rid of all memory
|
|
|
|
from the previous allocation strategy by deleting the renderer
|
|
|
|
after swapping.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if ( m.isEmpty() != d->customRenderMode.isEmpty() )
|
2020-03-11 14:34:50 +01:00
|
|
|
scheduleRenderJob( new RenderJob( this, m ), AfterSwapStage );
|
2017-07-21 18:21:34 +02:00
|
|
|
else
|
|
|
|
d->customRenderMode = m;
|
|
|
|
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* QskWindow::customRenderMode() const
|
|
|
|
{
|
|
|
|
Q_D( const QskWindow );
|
|
|
|
return d->customRenderMode;
|
|
|
|
}
|
|
|
|
|
|
|
|
void QskWindow::enforceSkin()
|
|
|
|
{
|
|
|
|
if ( !qskEnforcedSkin )
|
|
|
|
{
|
|
|
|
// usually the skin is set in the application startup code, but if not
|
|
|
|
// let's create a default skin on the GUI thread - whatever it is
|
|
|
|
// good for.
|
|
|
|
|
2018-08-03 08:15:28 +02:00
|
|
|
( void ) qskSetup->skin();
|
2017-07-21 18:21:34 +02:00
|
|
|
qskEnforcedSkin = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
disconnect( this, &QQuickWindow::afterAnimating, this, &QskWindow::enforceSkin );
|
|
|
|
}
|
|
|
|
|
2018-06-25 12:36:15 +02:00
|
|
|
void QskWindow::setEventAcceptance( EventAcceptance acceptance )
|
|
|
|
{
|
|
|
|
d_func()->eventAcceptance = acceptance;
|
|
|
|
}
|
|
|
|
|
|
|
|
QskWindow::EventAcceptance QskWindow::eventAcceptance() const
|
|
|
|
{
|
|
|
|
return d_func()->eventAcceptance;
|
|
|
|
}
|
|
|
|
|
2017-07-21 18:21:34 +02:00
|
|
|
#include "moc_QskWindow.cpp"
|