commit
1ffba57fcd
|
@ -1,4 +1,4 @@
|
||||||
qtbase-opensource-src (5.15.8+dfsg-ok1.1test2) yangtze; urgency=medium
|
qtbase-opensource-src (5.15.8+dfsg-ok1.1test3) yangtze; urgency=medium
|
||||||
|
|
||||||
* rebuild
|
* rebuild
|
||||||
|
|
||||||
|
|
|
@ -176,6 +176,39 @@ void ThreadEngineBase::startSingleThreaded()
|
||||||
finish();
|
finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ThreadEngineBase::startBlocking()
|
||||||
|
{
|
||||||
|
start();
|
||||||
|
barrier.acquire();
|
||||||
|
startThreads();
|
||||||
|
|
||||||
|
bool throttled = false;
|
||||||
|
#ifndef QT_NO_EXCEPTIONS
|
||||||
|
try {
|
||||||
|
#endif
|
||||||
|
while (threadFunction() == ThrottleThread) {
|
||||||
|
if (threadThrottleExit()) {
|
||||||
|
throttled = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifndef QT_NO_EXCEPTIONS
|
||||||
|
} catch (QException &e) {
|
||||||
|
handleException(e);
|
||||||
|
} catch (...) {
|
||||||
|
handleException(QUnhandledException());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (throttled == false) {
|
||||||
|
barrier.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
barrier.wait();
|
||||||
|
finish();
|
||||||
|
exceptionStore.throwPossibleException();
|
||||||
|
}
|
||||||
|
|
||||||
void ThreadEngineBase::startThread()
|
void ThreadEngineBase::startThread()
|
||||||
{
|
{
|
||||||
startThreadInternal();
|
startThreadInternal();
|
||||||
|
|
|
@ -91,6 +91,7 @@ public:
|
||||||
ThreadEngineBase();
|
ThreadEngineBase();
|
||||||
virtual ~ThreadEngineBase();
|
virtual ~ThreadEngineBase();
|
||||||
void startSingleThreaded();
|
void startSingleThreaded();
|
||||||
|
void startBlocking();
|
||||||
void startThread();
|
void startThread();
|
||||||
bool isCanceled();
|
bool isCanceled();
|
||||||
void waitForResume();
|
void waitForResume();
|
||||||
|
@ -143,6 +144,15 @@ public:
|
||||||
return result();
|
return result();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Runs the user algorithm using multiple threads.
|
||||||
|
// This function blocks until the algorithm is finished,
|
||||||
|
// and then returns the result.
|
||||||
|
T *startBlocking()
|
||||||
|
{
|
||||||
|
ThreadEngineBase::startBlocking();
|
||||||
|
return result();
|
||||||
|
}
|
||||||
|
|
||||||
// Runs the user algorithm using multiple threads.
|
// Runs the user algorithm using multiple threads.
|
||||||
// Does not block, returns a future.
|
// Does not block, returns a future.
|
||||||
QFuture<T> startAsynchronously()
|
QFuture<T> startAsynchronously()
|
||||||
|
@ -223,6 +233,13 @@ class ThreadEngineStarter : public ThreadEngineStarterBase<T>
|
||||||
public:
|
public:
|
||||||
ThreadEngineStarter(TypedThreadEngine *eng)
|
ThreadEngineStarter(TypedThreadEngine *eng)
|
||||||
: Base(eng) { }
|
: Base(eng) { }
|
||||||
|
|
||||||
|
T startBlocking()
|
||||||
|
{
|
||||||
|
T t = *this->threadEngine->startBlocking();
|
||||||
|
delete this->threadEngine;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Full template specialization where T is void.
|
// Full template specialization where T is void.
|
||||||
|
@ -232,6 +249,12 @@ class ThreadEngineStarter<void> : public ThreadEngineStarterBase<void>
|
||||||
public:
|
public:
|
||||||
ThreadEngineStarter(ThreadEngine<void> *_threadEngine)
|
ThreadEngineStarter(ThreadEngine<void> *_threadEngine)
|
||||||
: ThreadEngineStarterBase<void>(_threadEngine) {}
|
: ThreadEngineStarterBase<void>(_threadEngine) {}
|
||||||
|
|
||||||
|
void startBlocking()
|
||||||
|
{
|
||||||
|
this->threadEngine->startBlocking();
|
||||||
|
delete this->threadEngine;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//! [qtconcurrentthreadengine-1]
|
//! [qtconcurrentthreadengine-1]
|
||||||
|
|
|
@ -515,9 +515,9 @@ QImageReaderPrivate::QImageReaderPrivate(QImageReader *qq)
|
||||||
*/
|
*/
|
||||||
QImageReaderPrivate::~QImageReaderPrivate()
|
QImageReaderPrivate::~QImageReaderPrivate()
|
||||||
{
|
{
|
||||||
|
delete handler;
|
||||||
if (deleteDevice)
|
if (deleteDevice)
|
||||||
delete device;
|
delete device;
|
||||||
delete handler;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -774,12 +774,12 @@ bool QImageReader::decideFormatFromContent() const
|
||||||
*/
|
*/
|
||||||
void QImageReader::setDevice(QIODevice *device)
|
void QImageReader::setDevice(QIODevice *device)
|
||||||
{
|
{
|
||||||
|
delete d->handler;
|
||||||
|
d->handler = nullptr;
|
||||||
if (d->device && d->deleteDevice)
|
if (d->device && d->deleteDevice)
|
||||||
delete d->device;
|
delete d->device;
|
||||||
d->device = device;
|
d->device = device;
|
||||||
d->deleteDevice = false;
|
d->deleteDevice = false;
|
||||||
delete d->handler;
|
|
||||||
d->handler = nullptr;
|
|
||||||
d->text.clear();
|
d->text.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -349,9 +349,9 @@ QImageWriter::QImageWriter(const QString &fileName, const QByteArray &format)
|
||||||
*/
|
*/
|
||||||
QImageWriter::~QImageWriter()
|
QImageWriter::~QImageWriter()
|
||||||
{
|
{
|
||||||
|
delete d->handler;
|
||||||
if (d->deleteDevice)
|
if (d->deleteDevice)
|
||||||
delete d->device;
|
delete d->device;
|
||||||
delete d->handler;
|
|
||||||
delete d;
|
delete d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -396,13 +396,13 @@ QByteArray QImageWriter::format() const
|
||||||
*/
|
*/
|
||||||
void QImageWriter::setDevice(QIODevice *device)
|
void QImageWriter::setDevice(QIODevice *device)
|
||||||
{
|
{
|
||||||
|
delete d->handler;
|
||||||
|
d->handler = nullptr;
|
||||||
if (d->device && d->deleteDevice)
|
if (d->device && d->deleteDevice)
|
||||||
delete d->device;
|
delete d->device;
|
||||||
|
|
||||||
d->device = device;
|
d->device = device;
|
||||||
d->deleteDevice = false;
|
d->deleteDevice = false;
|
||||||
delete d->handler;
|
|
||||||
d->handler = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
|
@ -1412,14 +1412,7 @@ void QGuiApplicationPrivate::createPlatformIntegration()
|
||||||
if (sessionType == QByteArrayLiteral("x11") && !platformName.contains(QByteArrayLiteral("xcb"))) {
|
if (sessionType == QByteArrayLiteral("x11") && !platformName.contains(QByteArrayLiteral("xcb"))) {
|
||||||
platformName = QByteArrayLiteral("xcb");
|
platformName = QByteArrayLiteral("xcb");
|
||||||
} else if (sessionType == QByteArrayLiteral("wayland") && !platformName.contains(QByteArrayLiteral("wayland"))) {
|
} else if (sessionType == QByteArrayLiteral("wayland") && !platformName.contains(QByteArrayLiteral("wayland"))) {
|
||||||
QByteArray currentDesktop = qgetenv("XDG_CURRENT_DESKTOP").toLower();
|
platformName = QByteArrayLiteral("wayland");
|
||||||
QByteArray sessionDesktop = qgetenv("XDG_SESSION_DESKTOP").toLower();
|
|
||||||
if (currentDesktop.contains("gnome") || sessionDesktop.contains("gnome")) {
|
|
||||||
qInfo() << "Warning: Ignoring XDG_SESSION_TYPE=wayland on Gnome."
|
|
||||||
<< "Use QT_QPA_PLATFORM=wayland to run on Wayland anyway.";
|
|
||||||
} else {
|
|
||||||
platformName = QByteArrayLiteral("wayland");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef QT_QPA_DEFAULT_PLATFORM_NAME
|
#ifdef QT_QPA_DEFAULT_PLATFORM_NAME
|
||||||
|
@ -3064,8 +3057,7 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
|
||||||
QEvent::Type mouseEventType = QEvent::MouseMove;
|
QEvent::Type mouseEventType = QEvent::MouseMove;
|
||||||
Qt::MouseButton button = Qt::NoButton;
|
Qt::MouseButton button = Qt::NoButton;
|
||||||
Qt::MouseButtons buttons = Qt::LeftButton;
|
Qt::MouseButtons buttons = Qt::LeftButton;
|
||||||
if ((eventType == QEvent::TouchBegin && m_fakeMouseSourcePointId < 0)
|
if (eventType == QEvent::TouchBegin && m_fakeMouseSourcePointId < 0)
|
||||||
|| (touchPoints.count() == 1 && m_fakeMouseSourcePointId != touchPoints.first().id()))
|
|
||||||
m_fakeMouseSourcePointId = touchPoints.first().id();
|
m_fakeMouseSourcePointId = touchPoints.first().id();
|
||||||
for (const auto &touchPoint : touchPoints) {
|
for (const auto &touchPoint : touchPoints) {
|
||||||
if (touchPoint.id() == m_fakeMouseSourcePointId) {
|
if (touchPoint.id() == m_fakeMouseSourcePointId) {
|
||||||
|
|
|
@ -455,7 +455,7 @@ init_context:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable bug workarounds.
|
// Enable bug workarounds.
|
||||||
long options = QSslSocketBackendPrivate::setupOpenSslOptions(configuration.protocol(), configuration.d->sslOptions);
|
qssloptions options = QSslSocketBackendPrivate::setupOpenSslOptions(configuration.protocol(), configuration.d->sslOptions);
|
||||||
q_SSL_CTX_set_options(sslContext->ctx, options);
|
q_SSL_CTX_set_options(sslContext->ctx, options);
|
||||||
|
|
||||||
// Tell OpenSSL to release memory early
|
// Tell OpenSSL to release memory early
|
||||||
|
|
|
@ -550,9 +550,9 @@ static void q_loadCiphersForConnection(SSL *connection, QList<QSslCipher> &ciphe
|
||||||
// Defined in qsslsocket.cpp
|
// Defined in qsslsocket.cpp
|
||||||
void q_setDefaultDtlsCiphers(const QList<QSslCipher> &ciphers);
|
void q_setDefaultDtlsCiphers(const QList<QSslCipher> &ciphers);
|
||||||
|
|
||||||
long QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SslProtocol protocol, QSsl::SslOptions sslOptions)
|
qssloptions QSslSocketBackendPrivate::setupOpenSslOptions(QSsl::SslProtocol protocol, QSsl::SslOptions sslOptions)
|
||||||
{
|
{
|
||||||
long options;
|
qssloptions options;
|
||||||
if (protocol == QSsl::TlsV1SslV3)
|
if (protocol == QSsl::TlsV1SslV3)
|
||||||
options = SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3;
|
options = SSL_OP_ALL|SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3;
|
||||||
else if (protocol == QSsl::SecureProtocols)
|
else if (protocol == QSsl::SecureProtocols)
|
||||||
|
|
|
@ -107,6 +107,12 @@
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
#if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3
|
||||||
|
typedef uint64_t qssloptions;
|
||||||
|
#else
|
||||||
|
typedef unsigned long qssloptions;
|
||||||
|
#endif
|
||||||
|
|
||||||
struct QSslErrorEntry {
|
struct QSslErrorEntry {
|
||||||
int code;
|
int code;
|
||||||
int depth;
|
int depth;
|
||||||
|
@ -171,7 +177,7 @@ public:
|
||||||
QVector<QSslError> ocspErrors;
|
QVector<QSslError> ocspErrors;
|
||||||
QByteArray ocspResponseDer;
|
QByteArray ocspResponseDer;
|
||||||
|
|
||||||
Q_AUTOTEST_EXPORT static long setupOpenSslOptions(QSsl::SslProtocol protocol, QSsl::SslOptions sslOptions);
|
Q_AUTOTEST_EXPORT static qssloptions setupOpenSslOptions(QSsl::SslProtocol protocol, QSsl::SslOptions sslOptions);
|
||||||
static QSslCipher QSslCipher_from_SSL_CIPHER(const SSL_CIPHER *cipher);
|
static QSslCipher QSslCipher_from_SSL_CIPHER(const SSL_CIPHER *cipher);
|
||||||
static QList<QSslCertificate> STACKOFX509_to_QSslCertificates(STACK_OF(X509) *x509);
|
static QList<QSslCertificate> STACKOFX509_to_QSslCertificates(STACK_OF(X509) *x509);
|
||||||
static QList<QSslError> verify(const QList<QSslCertificate> &certificateChain, const QString &hostName);
|
static QList<QSslError> verify(const QList<QSslCertificate> &certificateChain, const QString &hostName);
|
||||||
|
|
|
@ -157,7 +157,7 @@ DEFINEFUNC2(void, OPENSSL_sk_push, OPENSSL_STACK *a, a, void *b, b, return, DUMM
|
||||||
DEFINEFUNC(void, OPENSSL_sk_free, OPENSSL_STACK *a, a, return, DUMMYARG)
|
DEFINEFUNC(void, OPENSSL_sk_free, OPENSSL_STACK *a, a, return, DUMMYARG)
|
||||||
DEFINEFUNC2(void *, OPENSSL_sk_value, OPENSSL_STACK *a, a, int b, b, return nullptr, return)
|
DEFINEFUNC2(void *, OPENSSL_sk_value, OPENSSL_STACK *a, a, int b, b, return nullptr, return)
|
||||||
DEFINEFUNC(int, SSL_session_reused, SSL *a, a, return 0, return)
|
DEFINEFUNC(int, SSL_session_reused, SSL *a, a, return 0, return)
|
||||||
DEFINEFUNC2(unsigned long, SSL_CTX_set_options, SSL_CTX *ctx, ctx, unsigned long op, op, return 0, return)
|
DEFINEFUNC2(qssloptions, SSL_CTX_set_options, SSL_CTX *ctx, ctx, qssloptions op, op, return 0, return)
|
||||||
DEFINEFUNC(int, SSL_CTX_get_security_level, const SSL_CTX *ctx, ctx, return -1, return)
|
DEFINEFUNC(int, SSL_CTX_get_security_level, const SSL_CTX *ctx, ctx, return -1, return)
|
||||||
DEFINEFUNC2(void, SSL_CTX_set_security_level, SSL_CTX *ctx, ctx, int level, level, return, return)
|
DEFINEFUNC2(void, SSL_CTX_set_security_level, SSL_CTX *ctx, ctx, int level, level, return, return)
|
||||||
#ifdef TLS1_3_VERSION
|
#ifdef TLS1_3_VERSION
|
||||||
|
|
|
@ -245,7 +245,7 @@ Q_AUTOTEST_EXPORT void q_OPENSSL_sk_push(OPENSSL_STACK *st, void *data);
|
||||||
Q_AUTOTEST_EXPORT void q_OPENSSL_sk_free(OPENSSL_STACK *a);
|
Q_AUTOTEST_EXPORT void q_OPENSSL_sk_free(OPENSSL_STACK *a);
|
||||||
Q_AUTOTEST_EXPORT void * q_OPENSSL_sk_value(OPENSSL_STACK *a, int b);
|
Q_AUTOTEST_EXPORT void * q_OPENSSL_sk_value(OPENSSL_STACK *a, int b);
|
||||||
int q_SSL_session_reused(SSL *a);
|
int q_SSL_session_reused(SSL *a);
|
||||||
unsigned long q_SSL_CTX_set_options(SSL_CTX *ctx, unsigned long op);
|
qssloptions q_SSL_CTX_set_options(SSL_CTX *ctx, qssloptions op);
|
||||||
int q_OPENSSL_init_ssl(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings);
|
int q_OPENSSL_init_ssl(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings);
|
||||||
size_t q_SSL_get_client_random(SSL *a, unsigned char *out, size_t outlen);
|
size_t q_SSL_get_client_random(SSL *a, unsigned char *out, size_t outlen);
|
||||||
size_t q_SSL_SESSION_get_master_key(const SSL_SESSION *session, unsigned char *out, size_t outlen);
|
size_t q_SSL_SESSION_get_master_key(const SSL_SESSION *session, unsigned char *out, size_t outlen);
|
||||||
|
|
|
@ -471,7 +471,7 @@ QVector<xkb_keysym_t> QXkbCommon::toKeysym(QKeyEvent *event)
|
||||||
} else if (event->modifiers() & Qt::KeypadModifier) {
|
} else if (event->modifiers() & Qt::KeypadModifier) {
|
||||||
if (qtKey >= Qt::Key_0 && qtKey <= Qt::Key_9)
|
if (qtKey >= Qt::Key_0 && qtKey <= Qt::Key_9)
|
||||||
keysyms.append(XKB_KEY_KP_0 + (qtKey - Qt::Key_0));
|
keysyms.append(XKB_KEY_KP_0 + (qtKey - Qt::Key_0));
|
||||||
} else if (isLatin(qtKey) && event->text().isUpper()) {
|
} else if (isLatin1(qtKey) && event->text().isUpper()) {
|
||||||
keysyms.append(qtKey);
|
keysyms.append(qtKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -523,7 +523,7 @@ int QXkbCommon::keysymToQtKey(xkb_keysym_t keysym, Qt::KeyboardModifiers modifie
|
||||||
// With standard shortcuts we should prefer a latin character, this is
|
// With standard shortcuts we should prefer a latin character, this is
|
||||||
// for checks like "some qkeyevent == QKeySequence::Copy" to work even
|
// for checks like "some qkeyevent == QKeySequence::Copy" to work even
|
||||||
// when using for example 'russian' keyboard layout.
|
// when using for example 'russian' keyboard layout.
|
||||||
if (!QXkbCommon::isLatin(keysym)) {
|
if (!QXkbCommon::isLatin1(keysym)) {
|
||||||
xkb_keysym_t latinKeysym = QXkbCommon::lookupLatinKeysym(state, code);
|
xkb_keysym_t latinKeysym = QXkbCommon::lookupLatinKeysym(state, code);
|
||||||
if (latinKeysym != XKB_KEY_NoSymbol)
|
if (latinKeysym != XKB_KEY_NoSymbol)
|
||||||
keysym = latinKeysym;
|
keysym = latinKeysym;
|
||||||
|
@ -546,7 +546,7 @@ static int keysymToQtKey_internal(xkb_keysym_t keysym, Qt::KeyboardModifiers mod
|
||||||
} else if (keysym >= XKB_KEY_KP_0 && keysym <= XKB_KEY_KP_9) {
|
} else if (keysym >= XKB_KEY_KP_0 && keysym <= XKB_KEY_KP_9) {
|
||||||
// numeric keypad keys
|
// numeric keypad keys
|
||||||
qtKey = Qt::Key_0 + (keysym - XKB_KEY_KP_0);
|
qtKey = Qt::Key_0 + (keysym - XKB_KEY_KP_0);
|
||||||
} else if (QXkbCommon::isLatin(keysym)) {
|
} else if (QXkbCommon::isLatin1(keysym)) {
|
||||||
qtKey = QXkbCommon::qxkbcommon_xkb_keysym_to_upper(keysym);
|
qtKey = QXkbCommon::qxkbcommon_xkb_keysym_to_upper(keysym);
|
||||||
} else {
|
} else {
|
||||||
// check if we have a direct mapping
|
// check if we have a direct mapping
|
||||||
|
@ -678,7 +678,7 @@ QList<int> QXkbCommon::possibleKeys(xkb_state *state, const QKeyEvent *event,
|
||||||
Qt::KeyboardModifiers neededMods = ModsTbl[i];
|
Qt::KeyboardModifiers neededMods = ModsTbl[i];
|
||||||
if ((modifiers & neededMods) == neededMods) {
|
if ((modifiers & neededMods) == neededMods) {
|
||||||
if (i == 8) {
|
if (i == 8) {
|
||||||
if (isLatin(baseQtKey))
|
if (isLatin1(baseQtKey))
|
||||||
continue;
|
continue;
|
||||||
// add a latin key as a fall back key
|
// add a latin key as a fall back key
|
||||||
sym = lookupLatinKeysym(state, keycode);
|
sym = lookupLatinKeysym(state, keycode);
|
||||||
|
@ -733,7 +733,7 @@ void QXkbCommon::verifyHasLatinLayout(xkb_keymap *keymap)
|
||||||
for (xkb_layout_index_t layout = 0; layout < layoutCount; ++layout) {
|
for (xkb_layout_index_t layout = 0; layout < layoutCount; ++layout) {
|
||||||
for (xkb_keycode_t code = minKeycode; code < maxKeycode; ++code) {
|
for (xkb_keycode_t code = minKeycode; code < maxKeycode; ++code) {
|
||||||
xkb_keymap_key_get_syms_by_level(keymap, code, layout, 0, &keysyms);
|
xkb_keymap_key_get_syms_by_level(keymap, code, layout, 0, &keysyms);
|
||||||
if (keysyms && isLatin(keysyms[0]))
|
if (keysyms && isLatin1(keysyms[0]))
|
||||||
nrLatinKeys++;
|
nrLatinKeys++;
|
||||||
if (nrLatinKeys > 10) // arbitrarily chosen threshold
|
if (nrLatinKeys > 10) // arbitrarily chosen threshold
|
||||||
return;
|
return;
|
||||||
|
@ -766,7 +766,7 @@ xkb_keysym_t QXkbCommon::lookupLatinKeysym(xkb_state *state, xkb_keycode_t keyco
|
||||||
xkb_level_index_t level = xkb_state_key_get_level(state, keycode, layout);
|
xkb_level_index_t level = xkb_state_key_get_level(state, keycode, layout);
|
||||||
if (xkb_keymap_key_get_syms_by_level(keymap, keycode, layout, level, &syms) != 1)
|
if (xkb_keymap_key_get_syms_by_level(keymap, keycode, layout, level, &syms) != 1)
|
||||||
continue;
|
continue;
|
||||||
if (isLatin(syms[0])) {
|
if (isLatin1(syms[0])) {
|
||||||
sym = syms[0];
|
sym = syms[0];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,8 +94,8 @@ public:
|
||||||
static void verifyHasLatinLayout(xkb_keymap *keymap);
|
static void verifyHasLatinLayout(xkb_keymap *keymap);
|
||||||
static xkb_keysym_t lookupLatinKeysym(xkb_state *state, xkb_keycode_t keycode);
|
static xkb_keysym_t lookupLatinKeysym(xkb_state *state, xkb_keycode_t keycode);
|
||||||
|
|
||||||
static bool isLatin(xkb_keysym_t sym) {
|
static bool isLatin1(xkb_keysym_t sym) {
|
||||||
return ((sym >= 'a' && sym <= 'z') || (sym >= 'A' && sym <= 'Z'));
|
return sym <= 0xff;
|
||||||
}
|
}
|
||||||
static bool isKeypad(xkb_keysym_t sym) {
|
static bool isKeypad(xkb_keysym_t sym) {
|
||||||
return sym >= XKB_KEY_KP_Space && sym <= XKB_KEY_KP_9;
|
return sym >= XKB_KEY_KP_Space && sym <= XKB_KEY_KP_9;
|
||||||
|
|
|
@ -593,10 +593,6 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
|
||||||
fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y),xiDeviceEvent->event);
|
fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y),xiDeviceEvent->event);
|
||||||
if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event))
|
if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event))
|
||||||
xi2ProcessTouch(xiDeviceEvent, platformWindow);
|
xi2ProcessTouch(xiDeviceEvent, platformWindow);
|
||||||
else { // When the window cannot be matched, delete it from touchPoints
|
|
||||||
if (TouchDeviceData *dev = touchDeviceForId(xiDeviceEvent->sourceid))
|
|
||||||
dev->touchPoints.remove((xiDeviceEvent->detail % INT_MAX));
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (xiEnterEvent && !xi2MouseEventsDisabled() && eventListener) {
|
} else if (xiEnterEvent && !xi2MouseEventsDisabled() && eventListener) {
|
||||||
|
|
|
@ -93,6 +93,8 @@ enum {
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
Q_LOGGING_CATEGORY(lcQpaWindow, "qt.qpa.window");
|
||||||
|
|
||||||
Q_DECLARE_TYPEINFO(xcb_rectangle_t, Q_PRIMITIVE_TYPE);
|
Q_DECLARE_TYPEINFO(xcb_rectangle_t, Q_PRIMITIVE_TYPE);
|
||||||
|
|
||||||
#undef FocusIn
|
#undef FocusIn
|
||||||
|
@ -297,11 +299,6 @@ void QXcbWindow::create()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPlatformWindow::setGeometry(rect);
|
|
||||||
|
|
||||||
if (platformScreen != currentScreen)
|
|
||||||
QWindowSystemInterface::handleWindowScreenChanged(window(), platformScreen->QPlatformScreen::screen());
|
|
||||||
|
|
||||||
const QSize minimumSize = windowMinimumSize();
|
const QSize minimumSize = windowMinimumSize();
|
||||||
if (rect.width() > 0 || rect.height() > 0) {
|
if (rect.width() > 0 || rect.height() > 0) {
|
||||||
rect.setWidth(qBound(1, rect.width(), XCOORD_MAX));
|
rect.setWidth(qBound(1, rect.width(), XCOORD_MAX));
|
||||||
|
@ -313,6 +310,11 @@ void QXcbWindow::create()
|
||||||
rect.setHeight(QHighDpi::toNativePixels(int(defaultWindowHeight), platformScreen->QPlatformScreen::screen()));
|
rect.setHeight(QHighDpi::toNativePixels(int(defaultWindowHeight), platformScreen->QPlatformScreen::screen()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPlatformWindow::setGeometry(rect);
|
||||||
|
|
||||||
|
if (platformScreen != currentScreen)
|
||||||
|
QWindowSystemInterface::handleWindowScreenChanged(window(), platformScreen->QPlatformScreen::screen());
|
||||||
|
|
||||||
xcb_window_t xcb_parent_id = platformScreen->root();
|
xcb_window_t xcb_parent_id = platformScreen->root();
|
||||||
if (parent()) {
|
if (parent()) {
|
||||||
xcb_parent_id = static_cast<QXcbWindow *>(parent())->xcb_window();
|
xcb_parent_id = static_cast<QXcbWindow *>(parent())->xcb_window();
|
||||||
|
@ -555,6 +557,7 @@ void QXcbWindow::destroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
m_mapped = false;
|
m_mapped = false;
|
||||||
|
m_recreationReasons = RecreationNotNeeded;
|
||||||
|
|
||||||
if (m_pendingSyncRequest)
|
if (m_pendingSyncRequest)
|
||||||
m_pendingSyncRequest->invalidate();
|
m_pendingSyncRequest->invalidate();
|
||||||
|
@ -564,11 +567,6 @@ void QXcbWindow::setGeometry(const QRect &rect)
|
||||||
{
|
{
|
||||||
QPlatformWindow::setGeometry(rect);
|
QPlatformWindow::setGeometry(rect);
|
||||||
|
|
||||||
if (shouldDeferTask(Task::SetGeometry)) {
|
|
||||||
m_deferredGeometry = rect;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
propagateSizeHints();
|
propagateSizeHints();
|
||||||
|
|
||||||
QXcbScreen *currentScreen = xcbScreen();
|
QXcbScreen *currentScreen = xcbScreen();
|
||||||
|
@ -693,10 +691,12 @@ void QXcbWindow::setVisible(bool visible)
|
||||||
|
|
||||||
void QXcbWindow::show()
|
void QXcbWindow::show()
|
||||||
{
|
{
|
||||||
if (shouldDeferTask(Task::Map))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (window()->isTopLevel()) {
|
if (window()->isTopLevel()) {
|
||||||
|
if (m_recreationReasons != RecreationNotNeeded) {
|
||||||
|
qCDebug(lcQpaWindow) << "QXcbWindow: need to recreate window" << window() << m_recreationReasons;
|
||||||
|
create();
|
||||||
|
m_recreationReasons = RecreationNotNeeded;
|
||||||
|
}
|
||||||
|
|
||||||
// update WM_NORMAL_HINTS
|
// update WM_NORMAL_HINTS
|
||||||
propagateSizeHints();
|
propagateSizeHints();
|
||||||
|
@ -746,10 +746,6 @@ void QXcbWindow::show()
|
||||||
|
|
||||||
void QXcbWindow::hide()
|
void QXcbWindow::hide()
|
||||||
{
|
{
|
||||||
if (shouldDeferTask(Task::Unmap))
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_wmStateValid = false;
|
|
||||||
xcb_unmap_window(xcb_connection(), m_window);
|
xcb_unmap_window(xcb_connection(), m_window);
|
||||||
|
|
||||||
// send synthetic UnmapNotify event according to icccm 4.1.4
|
// send synthetic UnmapNotify event according to icccm 4.1.4
|
||||||
|
@ -909,9 +905,6 @@ QXcbWindow::NetWmStates QXcbWindow::netWmStates()
|
||||||
|
|
||||||
void QXcbWindow::setWindowFlags(Qt::WindowFlags flags)
|
void QXcbWindow::setWindowFlags(Qt::WindowFlags flags)
|
||||||
{
|
{
|
||||||
if (shouldDeferTask(Task::SetWindowFlags))
|
|
||||||
return;
|
|
||||||
|
|
||||||
Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask));
|
Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask));
|
||||||
|
|
||||||
if (type == Qt::ToolTip)
|
if (type == Qt::ToolTip)
|
||||||
|
@ -919,6 +912,12 @@ void QXcbWindow::setWindowFlags(Qt::WindowFlags flags)
|
||||||
if (type == Qt::Popup)
|
if (type == Qt::Popup)
|
||||||
flags |= Qt::X11BypassWindowManagerHint;
|
flags |= Qt::X11BypassWindowManagerHint;
|
||||||
|
|
||||||
|
Qt::WindowFlags oldflags = window()->flags();
|
||||||
|
if ((oldflags & Qt::WindowStaysOnTopHint) != (flags & Qt::WindowStaysOnTopHint))
|
||||||
|
m_recreationReasons |= WindowStaysOnTopHintChanged;
|
||||||
|
if ((oldflags & Qt::WindowStaysOnBottomHint) != (flags & Qt::WindowStaysOnBottomHint))
|
||||||
|
m_recreationReasons |= WindowStaysOnBottomHintChanged;
|
||||||
|
|
||||||
const quint32 mask = XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK;
|
const quint32 mask = XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK;
|
||||||
const quint32 values[] = {
|
const quint32 values[] = {
|
||||||
// XCB_CW_OVERRIDE_REDIRECT
|
// XCB_CW_OVERRIDE_REDIRECT
|
||||||
|
@ -941,8 +940,6 @@ void QXcbWindow::setWindowFlags(Qt::WindowFlags flags)
|
||||||
|
|
||||||
setTransparentForMouseEvents(flags & Qt::WindowTransparentForInput);
|
setTransparentForMouseEvents(flags & Qt::WindowTransparentForInput);
|
||||||
updateDoesNotAcceptFocus(flags & Qt::WindowDoesNotAcceptFocus);
|
updateDoesNotAcceptFocus(flags & Qt::WindowDoesNotAcceptFocus);
|
||||||
|
|
||||||
m_isWmManagedWindow = !(flags & Qt::X11BypassWindowManagerHint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QXcbWindow::setMotifWmHints(Qt::WindowFlags flags)
|
void QXcbWindow::setMotifWmHints(Qt::WindowFlags flags)
|
||||||
|
@ -1142,9 +1139,6 @@ void QXcbWindow::setWindowState(Qt::WindowStates state)
|
||||||
if (state == m_windowState)
|
if (state == m_windowState)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (shouldDeferTask(Task::SetWindowState))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// unset old state
|
// unset old state
|
||||||
if (m_windowState & Qt::WindowMinimized)
|
if (m_windowState & Qt::WindowMinimized)
|
||||||
xcb_map_window(xcb_connection(), m_window);
|
xcb_map_window(xcb_connection(), m_window);
|
||||||
|
@ -1894,10 +1888,6 @@ void QXcbWindow::handleUnmapNotifyEvent(const xcb_unmap_notify_event_t *event)
|
||||||
if (event->window == m_window) {
|
if (event->window == m_window) {
|
||||||
m_mapped = false;
|
m_mapped = false;
|
||||||
QWindowSystemInterface::handleExposeEvent(window(), QRegion());
|
QWindowSystemInterface::handleExposeEvent(window(), QRegion());
|
||||||
if (!m_isWmManagedWindow || parent()) {
|
|
||||||
m_wmStateValid = true;
|
|
||||||
handleDeferredTasks();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2212,98 +2202,30 @@ void QXcbWindow::handleLeaveNotifyEvent(const xcb_leave_notify_event_t *event)
|
||||||
handleLeaveNotifyEvent(event->root_x, event->root_y, event->mode, event->detail, event->time);
|
handleLeaveNotifyEvent(event->root_x, event->root_y, event->mode, event->detail, event->time);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QXcbWindow::shouldDeferTask(Task task)
|
|
||||||
{
|
|
||||||
if (m_wmStateValid)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
m_deferredTasks.append(task);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void QXcbWindow::handleDeferredTasks()
|
|
||||||
{
|
|
||||||
Q_ASSERT(m_wmStateValid == true);
|
|
||||||
if (m_deferredTasks.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
bool map = false;
|
|
||||||
bool unmap = false;
|
|
||||||
|
|
||||||
QVector<Task> tasks;
|
|
||||||
for (auto taskIt = m_deferredTasks.rbegin(); taskIt != m_deferredTasks.rend(); ++taskIt) {
|
|
||||||
if (!tasks.contains(*taskIt))
|
|
||||||
tasks.prepend(*taskIt);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Task task : tasks) {
|
|
||||||
switch (task) {
|
|
||||||
case Task::Map:
|
|
||||||
map = true;
|
|
||||||
unmap = false;
|
|
||||||
break;
|
|
||||||
case Task::Unmap:
|
|
||||||
unmap = true;
|
|
||||||
map = false;
|
|
||||||
break;
|
|
||||||
case Task::SetGeometry:
|
|
||||||
setGeometry(m_deferredGeometry);
|
|
||||||
break;
|
|
||||||
case Task::SetWindowFlags:
|
|
||||||
setWindowFlags(window()->flags());
|
|
||||||
break;
|
|
||||||
case Task::SetWindowState:
|
|
||||||
setWindowState(window()->windowState());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_deferredTasks.clear();
|
|
||||||
|
|
||||||
if (map) {
|
|
||||||
Q_ASSERT(unmap == false);
|
|
||||||
show();
|
|
||||||
}
|
|
||||||
if (unmap) {
|
|
||||||
Q_ASSERT(map == false);
|
|
||||||
hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *event)
|
void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *event)
|
||||||
{
|
{
|
||||||
connection()->setTime(event->time);
|
connection()->setTime(event->time);
|
||||||
|
|
||||||
const bool wmStateChanged = event->atom == atom(QXcbAtom::WM_STATE);
|
const bool propertyDeleted = event->state == XCB_PROPERTY_DELETE;
|
||||||
const bool netWmStateChanged = event->atom == atom(QXcbAtom::_NET_WM_STATE);
|
|
||||||
if (netWmStateChanged || wmStateChanged) {
|
if (event->atom == atom(QXcbAtom::_NET_WM_STATE) || event->atom == atom(QXcbAtom::WM_STATE)) {
|
||||||
if (wmStateChanged && !m_wmStateValid && m_isWmManagedWindow) {
|
if (propertyDeleted)
|
||||||
// ICCCM 4.1.4
|
|
||||||
// Clients that want to re-use a client window (e.g. by mapping it again)
|
|
||||||
// after withdrawing it must wait for the withdrawal to be complete before
|
|
||||||
// proceeding. The preferred method for doing this is for clients to wait for
|
|
||||||
// a window manager to update or remove the WM_STATE property.
|
|
||||||
m_wmStateValid = true;
|
|
||||||
handleDeferredTasks();
|
|
||||||
}
|
|
||||||
if (event->state == XCB_PROPERTY_DELETE)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (wmStateChanged) {
|
Qt::WindowStates newState = Qt::WindowNoState;
|
||||||
|
|
||||||
|
if (event->atom == atom(QXcbAtom::WM_STATE)) { // WM_STATE: Quick check for 'Minimize'.
|
||||||
auto reply = Q_XCB_REPLY(xcb_get_property, xcb_connection(),
|
auto reply = Q_XCB_REPLY(xcb_get_property, xcb_connection(),
|
||||||
0, m_window, atom(QXcbAtom::WM_STATE),
|
0, m_window, atom(QXcbAtom::WM_STATE),
|
||||||
XCB_ATOM_ANY, 0, 1024);
|
XCB_ATOM_ANY, 0, 1024);
|
||||||
if (reply && reply->format == 32 && reply->type == atom(QXcbAtom::WM_STATE)) {
|
if (reply && reply->format == 32 && reply->type == atom(QXcbAtom::WM_STATE)) {
|
||||||
auto data = static_cast<const quint32 *>(xcb_get_property_value(reply.get()));
|
const quint32 *data = (const quint32 *)xcb_get_property_value(reply.get());
|
||||||
if (reply->length != 0) {
|
if (reply->length != 0)
|
||||||
const bool changedToWithdrawn = data[0] == XCB_ICCCM_WM_STATE_WITHDRAWN;
|
m_minimized = (data[0] == XCB_ICCCM_WM_STATE_ICONIC
|
||||||
const bool changedToIconic = data[0] == XCB_ICCCM_WM_STATE_ICONIC;
|
|| (data[0] == XCB_ICCCM_WM_STATE_WITHDRAWN && m_minimized));
|
||||||
m_minimized = changedToIconic || (changedToWithdrawn && m_minimized);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// _NET_WM_STATE handling
|
|
||||||
Qt::WindowStates newState = Qt::WindowNoState;
|
|
||||||
const NetWmStates states = netWmStates();
|
const NetWmStates states = netWmStates();
|
||||||
// _NET_WM_STATE_HIDDEN should be set by the Window Manager to indicate that a window would
|
// _NET_WM_STATE_HIDDEN should be set by the Window Manager to indicate that a window would
|
||||||
// not be visible on the screen if its desktop/viewport were active and its coordinates were
|
// not be visible on the screen if its desktop/viewport were active and its coordinates were
|
||||||
|
@ -2325,6 +2247,7 @@ void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *ev
|
||||||
if ((m_windowState & Qt::WindowMinimized) && connection()->mouseGrabber() == this)
|
if ((m_windowState & Qt::WindowMinimized) && connection()->mouseGrabber() == this)
|
||||||
connection()->setMouseGrabber(nullptr);
|
connection()->setMouseGrabber(nullptr);
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
} else if (event->atom == atom(QXcbAtom::_NET_FRAME_EXTENTS)) {
|
} else if (event->atom == atom(QXcbAtom::_NET_FRAME_EXTENTS)) {
|
||||||
m_dirtyFrameMargins = true;
|
m_dirtyFrameMargins = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,13 +74,12 @@ public:
|
||||||
|
|
||||||
Q_DECLARE_FLAGS(NetWmStates, NetWmState)
|
Q_DECLARE_FLAGS(NetWmStates, NetWmState)
|
||||||
|
|
||||||
enum Task {
|
enum RecreationReason {
|
||||||
Map,
|
RecreationNotNeeded = 0,
|
||||||
Unmap,
|
WindowStaysOnTopHintChanged = 0x1,
|
||||||
SetGeometry,
|
WindowStaysOnBottomHintChanged = 0x2
|
||||||
SetWindowFlags,
|
|
||||||
SetWindowState
|
|
||||||
};
|
};
|
||||||
|
Q_DECLARE_FLAGS(RecreationReasons, RecreationReason)
|
||||||
|
|
||||||
QXcbWindow(QWindow *window);
|
QXcbWindow(QWindow *window);
|
||||||
~QXcbWindow();
|
~QXcbWindow();
|
||||||
|
@ -151,9 +150,6 @@ public:
|
||||||
|
|
||||||
QXcbWindow *toWindow() override;
|
QXcbWindow *toWindow() override;
|
||||||
|
|
||||||
bool shouldDeferTask(Task task);
|
|
||||||
void handleDeferredTasks();
|
|
||||||
|
|
||||||
void handleMouseEvent(xcb_timestamp_t time, const QPoint &local, const QPoint &global,
|
void handleMouseEvent(xcb_timestamp_t time, const QPoint &local, const QPoint &global,
|
||||||
Qt::KeyboardModifiers modifiers, QEvent::Type type, Qt::MouseEventSource source);
|
Qt::KeyboardModifiers modifiers, QEvent::Type type, Qt::MouseEventSource source);
|
||||||
|
|
||||||
|
@ -293,10 +289,7 @@ protected:
|
||||||
|
|
||||||
qreal m_sizeHintsScaleFactor = 1.0;
|
qreal m_sizeHintsScaleFactor = 1.0;
|
||||||
|
|
||||||
bool m_wmStateValid = true;
|
RecreationReasons m_recreationReasons = RecreationNotNeeded;
|
||||||
QVector<Task> m_deferredTasks;
|
|
||||||
bool m_isWmManagedWindow = true;
|
|
||||||
QRect m_deferredGeometry;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class QXcbForeignWindow : public QXcbWindow
|
class QXcbForeignWindow : public QXcbWindow
|
||||||
|
|
|
@ -92,23 +92,39 @@ inline static QString fromSQLTCHAR(const QVarLengthArray<SQLTCHAR>& input, int s
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <size_t SizeOfChar = sizeof(SQLTCHAR)>
|
||||||
|
void toSQLTCHARImpl(QVarLengthArray<SQLTCHAR> &result, const QString &input); // primary template undefined
|
||||||
|
|
||||||
|
template <typename Container>
|
||||||
|
void do_append(QVarLengthArray<SQLTCHAR> &result, const Container &c)
|
||||||
|
{
|
||||||
|
result.append(reinterpret_cast<const SQLTCHAR *>(c.data()), c.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void toSQLTCHARImpl<1>(QVarLengthArray<SQLTCHAR> &result, const QString &input)
|
||||||
|
{
|
||||||
|
const auto u8 = input.toUtf8();
|
||||||
|
do_append(result, u8);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void toSQLTCHARImpl<2>(QVarLengthArray<SQLTCHAR> &result, const QString &input)
|
||||||
|
{
|
||||||
|
do_append(result, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void toSQLTCHARImpl<4>(QVarLengthArray<SQLTCHAR> &result, const QString &input)
|
||||||
|
{
|
||||||
|
const auto u32 = input.toUcs4();
|
||||||
|
do_append(result, u32);
|
||||||
|
}
|
||||||
|
|
||||||
inline static QVarLengthArray<SQLTCHAR> toSQLTCHAR(const QString &input)
|
inline static QVarLengthArray<SQLTCHAR> toSQLTCHAR(const QString &input)
|
||||||
{
|
{
|
||||||
QVarLengthArray<SQLTCHAR> result;
|
QVarLengthArray<SQLTCHAR> result;
|
||||||
result.resize(input.size());
|
toSQLTCHARImpl(result, input);
|
||||||
switch(sizeof(SQLTCHAR)) {
|
|
||||||
case 1:
|
|
||||||
memcpy(result.data(), input.toUtf8().data(), input.size());
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
memcpy(result.data(), input.unicode(), input.size() * 2);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
memcpy(result.data(), input.toUcs4().data(), input.size() * 4);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
qCritical("sizeof(SQLTCHAR) is %d. Don't know how to handle this.", int(sizeof(SQLTCHAR)));
|
|
||||||
}
|
|
||||||
result.append(0); // make sure it's null terminated, doesn't matter if it already is, it does if it isn't.
|
result.append(0); // make sure it's null terminated, doesn't matter if it already is, it does if it isn't.
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -763,6 +779,14 @@ QChar QODBCDriverPrivate::quoteChar()
|
||||||
return quote;
|
return quote;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SQLRETURN qt_string_SQLSetConnectAttr(SQLHDBC handle, SQLINTEGER attr, const QString &val)
|
||||||
|
{
|
||||||
|
auto encoded = toSQLTCHAR(val);
|
||||||
|
return SQLSetConnectAttr(handle, attr,
|
||||||
|
encoded.data(),
|
||||||
|
SQLINTEGER(encoded.size() * sizeof(SQLTCHAR))); // size in bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool QODBCDriverPrivate::setConnectionOptions(const QString& connOpts)
|
bool QODBCDriverPrivate::setConnectionOptions(const QString& connOpts)
|
||||||
{
|
{
|
||||||
|
@ -798,10 +822,7 @@ bool QODBCDriverPrivate::setConnectionOptions(const QString& connOpts)
|
||||||
v = val.toUInt();
|
v = val.toUInt();
|
||||||
r = SQLSetConnectAttr(hDbc, SQL_ATTR_LOGIN_TIMEOUT, (SQLPOINTER) size_t(v), 0);
|
r = SQLSetConnectAttr(hDbc, SQL_ATTR_LOGIN_TIMEOUT, (SQLPOINTER) size_t(v), 0);
|
||||||
} else if (opt.toUpper() == QLatin1String("SQL_ATTR_CURRENT_CATALOG")) {
|
} else if (opt.toUpper() == QLatin1String("SQL_ATTR_CURRENT_CATALOG")) {
|
||||||
val.utf16(); // 0 terminate
|
r = qt_string_SQLSetConnectAttr(hDbc, SQL_ATTR_CURRENT_CATALOG, val);
|
||||||
r = SQLSetConnectAttr(hDbc, SQL_ATTR_CURRENT_CATALOG,
|
|
||||||
toSQLTCHAR(val).data(),
|
|
||||||
val.length()*sizeof(SQLTCHAR));
|
|
||||||
} else if (opt.toUpper() == QLatin1String("SQL_ATTR_METADATA_ID")) {
|
} else if (opt.toUpper() == QLatin1String("SQL_ATTR_METADATA_ID")) {
|
||||||
if (val.toUpper() == QLatin1String("SQL_TRUE")) {
|
if (val.toUpper() == QLatin1String("SQL_TRUE")) {
|
||||||
v = SQL_TRUE;
|
v = SQL_TRUE;
|
||||||
|
@ -816,10 +837,7 @@ bool QODBCDriverPrivate::setConnectionOptions(const QString& connOpts)
|
||||||
v = val.toUInt();
|
v = val.toUInt();
|
||||||
r = SQLSetConnectAttr(hDbc, SQL_ATTR_PACKET_SIZE, (SQLPOINTER) size_t(v), 0);
|
r = SQLSetConnectAttr(hDbc, SQL_ATTR_PACKET_SIZE, (SQLPOINTER) size_t(v), 0);
|
||||||
} else if (opt.toUpper() == QLatin1String("SQL_ATTR_TRACEFILE")) {
|
} else if (opt.toUpper() == QLatin1String("SQL_ATTR_TRACEFILE")) {
|
||||||
val.utf16(); // 0 terminate
|
r = qt_string_SQLSetConnectAttr(hDbc, SQL_ATTR_TRACEFILE, val);
|
||||||
r = SQLSetConnectAttr(hDbc, SQL_ATTR_TRACEFILE,
|
|
||||||
toSQLTCHAR(val).data(),
|
|
||||||
val.length()*sizeof(SQLTCHAR));
|
|
||||||
} else if (opt.toUpper() == QLatin1String("SQL_ATTR_TRACE")) {
|
} else if (opt.toUpper() == QLatin1String("SQL_ATTR_TRACE")) {
|
||||||
if (val.toUpper() == QLatin1String("SQL_OPT_TRACE_OFF")) {
|
if (val.toUpper() == QLatin1String("SQL_OPT_TRACE_OFF")) {
|
||||||
v = SQL_OPT_TRACE_OFF;
|
v = SQL_OPT_TRACE_OFF;
|
||||||
|
@ -1022,9 +1040,12 @@ bool QODBCResult::reset (const QString& query)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = SQLExecDirect(d->hStmt,
|
{
|
||||||
toSQLTCHAR(query).data(),
|
auto encoded = toSQLTCHAR(query);
|
||||||
(SQLINTEGER) query.length());
|
r = SQLExecDirect(d->hStmt,
|
||||||
|
encoded.data(),
|
||||||
|
SQLINTEGER(encoded.size()));
|
||||||
|
}
|
||||||
if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO && r!= SQL_NO_DATA) {
|
if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO && r!= SQL_NO_DATA) {
|
||||||
setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
|
setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
|
||||||
"Unable to execute statement"), QSqlError::StatementError, d));
|
"Unable to execute statement"), QSqlError::StatementError, d));
|
||||||
|
@ -1371,9 +1392,12 @@ bool QODBCResult::prepare(const QString& query)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = SQLPrepare(d->hStmt,
|
{
|
||||||
toSQLTCHAR(query).data(),
|
auto encoded = toSQLTCHAR(query);
|
||||||
(SQLINTEGER) query.length());
|
r = SQLPrepare(d->hStmt,
|
||||||
|
encoded.data(),
|
||||||
|
SQLINTEGER(encoded.size()));
|
||||||
|
}
|
||||||
|
|
||||||
if (r != SQL_SUCCESS) {
|
if (r != SQL_SUCCESS) {
|
||||||
setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
|
setLastError(qMakeError(QCoreApplication::translate("QODBCResult",
|
||||||
|
@ -1401,7 +1425,7 @@ bool QODBCResult::exec()
|
||||||
SQLCloseCursor(d->hStmt);
|
SQLCloseCursor(d->hStmt);
|
||||||
|
|
||||||
QVector<QVariant>& values = boundValues();
|
QVector<QVariant>& values = boundValues();
|
||||||
QVector<QByteArray> tmpStorage(values.count(), QByteArray()); // holds temporary buffers
|
QVector<QByteArray> tmpStorage(values.count(), QByteArray()); // targets for SQLBindParameter()
|
||||||
QVarLengthArray<SQLLEN, 32> indicators(values.count());
|
QVarLengthArray<SQLLEN, 32> indicators(values.count());
|
||||||
memset(indicators.data(), 0, indicators.size() * sizeof(SQLLEN));
|
memset(indicators.data(), 0, indicators.size() * sizeof(SQLLEN));
|
||||||
|
|
||||||
|
@ -1580,35 +1604,36 @@ bool QODBCResult::exec()
|
||||||
case QVariant::String:
|
case QVariant::String:
|
||||||
if (d->unicode) {
|
if (d->unicode) {
|
||||||
QByteArray &ba = tmpStorage[i];
|
QByteArray &ba = tmpStorage[i];
|
||||||
QString str = val.toString();
|
{
|
||||||
|
const auto encoded = toSQLTCHAR(val.toString());
|
||||||
|
ba = QByteArray(reinterpret_cast<const char *>(encoded.data()),
|
||||||
|
encoded.size() * sizeof(SQLTCHAR));
|
||||||
|
}
|
||||||
|
|
||||||
if (*ind != SQL_NULL_DATA)
|
if (*ind != SQL_NULL_DATA)
|
||||||
*ind = str.length() * sizeof(SQLTCHAR);
|
*ind = ba.size();
|
||||||
int strSize = str.length() * sizeof(SQLTCHAR);
|
|
||||||
|
|
||||||
if (bindValueType(i) & QSql::Out) {
|
if (bindValueType(i) & QSql::Out) {
|
||||||
const QVarLengthArray<SQLTCHAR> a(toSQLTCHAR(str));
|
|
||||||
ba = QByteArray((const char *)a.constData(), a.size() * sizeof(SQLTCHAR));
|
|
||||||
r = SQLBindParameter(d->hStmt,
|
r = SQLBindParameter(d->hStmt,
|
||||||
i + 1,
|
i + 1,
|
||||||
qParamType[bindValueType(i) & QSql::InOut],
|
qParamType[bindValueType(i) & QSql::InOut],
|
||||||
SQL_C_TCHAR,
|
SQL_C_TCHAR,
|
||||||
strSize > 254 ? SQL_WLONGVARCHAR : SQL_WVARCHAR,
|
ba.size() > 254 ? SQL_WLONGVARCHAR : SQL_WVARCHAR,
|
||||||
0, // god knows... don't change this!
|
0, // god knows... don't change this!
|
||||||
0,
|
0,
|
||||||
ba.data(),
|
const_cast<char *>(ba.constData()), // don't detach
|
||||||
ba.size(),
|
ba.size(),
|
||||||
ind);
|
ind);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ba = QByteArray ((const char *)toSQLTCHAR(str).constData(), str.size()*sizeof(SQLTCHAR));
|
|
||||||
r = SQLBindParameter(d->hStmt,
|
r = SQLBindParameter(d->hStmt,
|
||||||
i + 1,
|
i + 1,
|
||||||
qParamType[bindValueType(i) & QSql::InOut],
|
qParamType[bindValueType(i) & QSql::InOut],
|
||||||
SQL_C_TCHAR,
|
SQL_C_TCHAR,
|
||||||
strSize > 254 ? SQL_WLONGVARCHAR : SQL_WVARCHAR,
|
ba.size() > 254 ? SQL_WLONGVARCHAR : SQL_WVARCHAR,
|
||||||
strSize,
|
ba.size(),
|
||||||
0,
|
0,
|
||||||
const_cast<char *>(ba.constData()),
|
const_cast<char *>(ba.constData()), // don't detach
|
||||||
ba.size(),
|
ba.size(),
|
||||||
ind);
|
ind);
|
||||||
break;
|
break;
|
||||||
|
@ -1716,10 +1741,11 @@ bool QODBCResult::exec()
|
||||||
case QVariant::String:
|
case QVariant::String:
|
||||||
if (d->unicode) {
|
if (d->unicode) {
|
||||||
if (bindValueType(i) & QSql::Out) {
|
if (bindValueType(i) & QSql::Out) {
|
||||||
const QByteArray &first = tmpStorage.at(i);
|
const QByteArray &bytes = tmpStorage.at(i);
|
||||||
QVarLengthArray<SQLTCHAR> array;
|
const auto strSize = bytes.size() / int(sizeof(SQLTCHAR));
|
||||||
array.append((const SQLTCHAR *)first.constData(), first.size());
|
QVarLengthArray<SQLTCHAR> string(strSize);
|
||||||
values[i] = fromSQLTCHAR(array, first.size()/sizeof(SQLTCHAR));
|
memcpy(string.data(), bytes.data(), strSize * sizeof(SQLTCHAR));
|
||||||
|
values[i] = fromSQLTCHAR(string);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1966,14 +1992,16 @@ bool QODBCDriver::open(const QString & db,
|
||||||
SQLSMALLINT cb;
|
SQLSMALLINT cb;
|
||||||
QVarLengthArray<SQLTCHAR> connOut(1024);
|
QVarLengthArray<SQLTCHAR> connOut(1024);
|
||||||
memset(connOut.data(), 0, connOut.size() * sizeof(SQLTCHAR));
|
memset(connOut.data(), 0, connOut.size() * sizeof(SQLTCHAR));
|
||||||
r = SQLDriverConnect(d->hDbc,
|
{
|
||||||
NULL,
|
auto encoded = toSQLTCHAR(connQStr);
|
||||||
toSQLTCHAR(connQStr).data(),
|
r = SQLDriverConnect(d->hDbc,
|
||||||
(SQLSMALLINT)connQStr.length(),
|
nullptr,
|
||||||
connOut.data(),
|
encoded.data(), SQLSMALLINT(encoded.size()),
|
||||||
1024,
|
connOut.data(),
|
||||||
&cb,
|
1024,
|
||||||
/*SQL_DRIVER_NOPROMPT*/0);
|
&cb,
|
||||||
|
/*SQL_DRIVER_NOPROMPT*/0);
|
||||||
|
}
|
||||||
|
|
||||||
if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
|
if (r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO) {
|
||||||
setLastError(qMakeError(tr("Unable to connect"), QSqlError::ConnectionError, d));
|
setLastError(qMakeError(tr("Unable to connect"), QSqlError::ConnectionError, d));
|
||||||
|
@ -2352,17 +2380,15 @@ QStringList QODBCDriver::tables(QSql::TableType type) const
|
||||||
if (tableType.isEmpty())
|
if (tableType.isEmpty())
|
||||||
return tl;
|
return tl;
|
||||||
|
|
||||||
QString joinedTableTypeString = tableType.join(QLatin1Char(','));
|
{
|
||||||
|
auto joinedTableTypeString = toSQLTCHAR(tableType.join(u','));
|
||||||
|
|
||||||
r = SQLTables(hStmt,
|
r = SQLTables(hStmt,
|
||||||
NULL,
|
nullptr, 0,
|
||||||
0,
|
nullptr, 0,
|
||||||
NULL,
|
nullptr, 0,
|
||||||
0,
|
joinedTableTypeString.data(), joinedTableTypeString.size());
|
||||||
NULL,
|
}
|
||||||
0,
|
|
||||||
toSQLTCHAR(joinedTableTypeString).data(),
|
|
||||||
joinedTableTypeString.length() /* characters, not bytes */);
|
|
||||||
|
|
||||||
if (r != SQL_SUCCESS)
|
if (r != SQL_SUCCESS)
|
||||||
qSqlWarning(QLatin1String("QODBCDriver::tables Unable to execute table list"), d);
|
qSqlWarning(QLatin1String("QODBCDriver::tables Unable to execute table list"), d);
|
||||||
|
@ -2436,28 +2462,30 @@ QSqlIndex QODBCDriver::primaryIndex(const QString& tablename) const
|
||||||
SQL_ATTR_CURSOR_TYPE,
|
SQL_ATTR_CURSOR_TYPE,
|
||||||
(SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
|
(SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
|
||||||
SQL_IS_UINTEGER);
|
SQL_IS_UINTEGER);
|
||||||
r = SQLPrimaryKeys(hStmt,
|
{
|
||||||
catalog.length() == 0 ? NULL : toSQLTCHAR(catalog).data(),
|
auto c = toSQLTCHAR(catalog);
|
||||||
catalog.length(),
|
auto s = toSQLTCHAR(schema);
|
||||||
schema.length() == 0 ? NULL : toSQLTCHAR(schema).data(),
|
auto t = toSQLTCHAR(table);
|
||||||
schema.length(),
|
r = SQLPrimaryKeys(hStmt,
|
||||||
toSQLTCHAR(table).data(),
|
catalog.isEmpty() ? nullptr : c.data(), c.size(),
|
||||||
table.length() /* in characters, not in bytes */);
|
schema.isEmpty() ? nullptr : s.data(), s.size(),
|
||||||
|
t.data(), t.size());
|
||||||
|
}
|
||||||
|
|
||||||
// if the SQLPrimaryKeys() call does not succeed (e.g the driver
|
// if the SQLPrimaryKeys() call does not succeed (e.g the driver
|
||||||
// does not support it) - try an alternative method to get hold of
|
// does not support it) - try an alternative method to get hold of
|
||||||
// the primary index (e.g MS Access and FoxPro)
|
// the primary index (e.g MS Access and FoxPro)
|
||||||
if (r != SQL_SUCCESS) {
|
if (r != SQL_SUCCESS) {
|
||||||
r = SQLSpecialColumns(hStmt,
|
auto c = toSQLTCHAR(catalog);
|
||||||
SQL_BEST_ROWID,
|
auto s = toSQLTCHAR(schema);
|
||||||
catalog.length() == 0 ? NULL : toSQLTCHAR(catalog).data(),
|
auto t = toSQLTCHAR(table);
|
||||||
catalog.length(),
|
r = SQLSpecialColumns(hStmt,
|
||||||
schema.length() == 0 ? NULL : toSQLTCHAR(schema).data(),
|
SQL_BEST_ROWID,
|
||||||
schema.length(),
|
catalog.isEmpty() ? nullptr : c.data(), c.size(),
|
||||||
toSQLTCHAR(table).data(),
|
schema.isEmpty() ? nullptr : s.data(), s.size(),
|
||||||
table.length(),
|
t.data(), t.size(),
|
||||||
SQL_SCOPE_CURROW,
|
SQL_SCOPE_CURROW,
|
||||||
SQL_NULLABLE);
|
SQL_NULLABLE);
|
||||||
|
|
||||||
if (r != SQL_SUCCESS) {
|
if (r != SQL_SUCCESS) {
|
||||||
qSqlWarning(QLatin1String("QODBCDriver::primaryIndex: Unable to execute primary key list"), d);
|
qSqlWarning(QLatin1String("QODBCDriver::primaryIndex: Unable to execute primary key list"), d);
|
||||||
|
@ -2538,15 +2566,17 @@ QSqlRecord QODBCDriver::record(const QString& tablename) const
|
||||||
SQL_ATTR_CURSOR_TYPE,
|
SQL_ATTR_CURSOR_TYPE,
|
||||||
(SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
|
(SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
|
||||||
SQL_IS_UINTEGER);
|
SQL_IS_UINTEGER);
|
||||||
r = SQLColumns(hStmt,
|
{
|
||||||
catalog.length() == 0 ? NULL : toSQLTCHAR(catalog).data(),
|
auto c = toSQLTCHAR(catalog);
|
||||||
catalog.length(),
|
auto s = toSQLTCHAR(schema);
|
||||||
schema.length() == 0 ? NULL : toSQLTCHAR(schema).data(),
|
auto t = toSQLTCHAR(table);
|
||||||
schema.length(),
|
r = SQLColumns(hStmt,
|
||||||
toSQLTCHAR(table).data(),
|
catalog.isEmpty() ? nullptr : c.data(), c.size(),
|
||||||
table.length(),
|
schema.isEmpty() ? nullptr : s.data(), s.size(),
|
||||||
NULL,
|
t.data(), t.size(),
|
||||||
0);
|
nullptr,
|
||||||
|
0);
|
||||||
|
}
|
||||||
if (r != SQL_SUCCESS)
|
if (r != SQL_SUCCESS)
|
||||||
qSqlWarning(QLatin1String("QODBCDriver::record: Unable to execute column list"), d);
|
qSqlWarning(QLatin1String("QODBCDriver::record: Unable to execute column list"), d);
|
||||||
|
|
||||||
|
|
|
@ -624,6 +624,29 @@ void QMenuPrivate::hideMenu(QMenu *menu)
|
||||||
menu->d_func()->causedPopup.widget = nullptr;
|
menu->d_func()->causedPopup.widget = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QWindow *QMenuPrivate::transientParentWindow() const
|
||||||
|
{
|
||||||
|
Q_Q(const QMenu);
|
||||||
|
if (const QWidget *parent = q->nativeParentWidget()) {
|
||||||
|
if (parent->windowHandle())
|
||||||
|
return parent->windowHandle();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const QWindow *w = q->windowHandle()) {
|
||||||
|
if (w->transientParent())
|
||||||
|
return w->transientParent();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (causedPopup.widget) {
|
||||||
|
if (const QWidget *w = causedPopup.widget.data()) {
|
||||||
|
if (const QWidget *ww = w->window())
|
||||||
|
return ww->windowHandle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void QMenuPrivate::popupAction(QAction *action, int delay, bool activateFirst)
|
void QMenuPrivate::popupAction(QAction *action, int delay, bool activateFirst)
|
||||||
{
|
{
|
||||||
Q_Q(QMenu);
|
Q_Q(QMenu);
|
||||||
|
@ -3060,6 +3083,8 @@ QMenu::event(QEvent *e)
|
||||||
d->sloppyState.reset();
|
d->sloppyState.reset();
|
||||||
if (d->currentAction)
|
if (d->currentAction)
|
||||||
d->popupAction(d->currentAction, 0, false);
|
d->popupAction(d->currentAction, 0, false);
|
||||||
|
if (isWindow() && window() && window()->windowHandle() && !window()->windowHandle()->transientParent())
|
||||||
|
window()->windowHandle()->setTransientParent(d->transientParentWindow());
|
||||||
break;
|
break;
|
||||||
#ifndef QT_NO_TOOLTIP
|
#ifndef QT_NO_TOOLTIP
|
||||||
case QEvent::ToolTip:
|
case QEvent::ToolTip:
|
||||||
|
|
|
@ -440,6 +440,7 @@ public:
|
||||||
QMenuCaused causedPopup;
|
QMenuCaused causedPopup;
|
||||||
void hideUpToMenuBar();
|
void hideUpToMenuBar();
|
||||||
void hideMenu(QMenu *menu);
|
void hideMenu(QMenu *menu);
|
||||||
|
QWindow *transientParentWindow() const;
|
||||||
|
|
||||||
//index mappings
|
//index mappings
|
||||||
inline QAction *actionAt(int i) const { return q_func()->actions().at(i); }
|
inline QAction *actionAt(int i) const { return q_func()->actions().at(i); }
|
||||||
|
|
|
@ -1498,7 +1498,7 @@ void tst_QApplication::desktopSettingsAware()
|
||||||
environment += QLatin1String("QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM=1");
|
environment += QLatin1String("QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM=1");
|
||||||
testProcess.setEnvironment(environment);
|
testProcess.setEnvironment(environment);
|
||||||
#endif
|
#endif
|
||||||
testProcess.start("desktopsettingsaware_helper");
|
testProcess.start("./desktopsettingsaware_helper");
|
||||||
QVERIFY2(testProcess.waitForStarted(),
|
QVERIFY2(testProcess.waitForStarted(),
|
||||||
qPrintable(QString::fromLatin1("Cannot start 'desktopsettingsaware_helper': %1").arg(testProcess.errorString())));
|
qPrintable(QString::fromLatin1("Cannot start 'desktopsettingsaware_helper': %1").arg(testProcess.errorString())));
|
||||||
QVERIFY(testProcess.waitForFinished(10000));
|
QVERIFY(testProcess.waitForFinished(10000));
|
||||||
|
@ -2452,7 +2452,7 @@ void tst_QApplication::qtbug_12673()
|
||||||
#if QT_CONFIG(process)
|
#if QT_CONFIG(process)
|
||||||
QProcess testProcess;
|
QProcess testProcess;
|
||||||
QStringList arguments;
|
QStringList arguments;
|
||||||
testProcess.start("modal_helper", arguments);
|
testProcess.start("./modal_helper", arguments);
|
||||||
QVERIFY2(testProcess.waitForStarted(),
|
QVERIFY2(testProcess.waitForStarted(),
|
||||||
qPrintable(QString::fromLatin1("Cannot start 'modal_helper': %1").arg(testProcess.errorString())));
|
qPrintable(QString::fromLatin1("Cannot start 'modal_helper': %1").arg(testProcess.errorString())));
|
||||||
QVERIFY(testProcess.waitForFinished(20000));
|
QVERIFY(testProcess.waitForFinished(20000));
|
||||||
|
|
Loading…
Reference in New Issue