Merge remote-tracking branch 'origin/5.13' into dev
Change-Id: I056b658ffe9390dfcbe2787e2bddc7f4e9b389dd
This commit is contained in:
commit
261c0dedac
@ -291,6 +291,8 @@ defineTest(qtConfTest_architecture) {
|
||||
content = $$cat($$test_out_dir/libarch.so, blob)
|
||||
else: wasm:exists($$test_out_dir/arch.wasm): \
|
||||
content = $$cat($$test_out_dir/arch.wasm, blob)
|
||||
else: wasm:exists($$test_out_dir/arch.o): \
|
||||
content = $$cat($$test_out_dir/arch.o, blob)
|
||||
else: \
|
||||
error("$$eval($${1}.label) detection binary not found.")
|
||||
|
||||
|
@ -5,6 +5,17 @@ QMAKE_PLATFORM = wasm unix
|
||||
include(../common/gcc-base.conf)
|
||||
include(../common/clang.conf)
|
||||
|
||||
load(device_config)
|
||||
|
||||
# Support setting WASM_OBJECT_FILES with -device-option WASM_OBJECT_FILES=1
|
||||
!isEmpty(WASM_OBJECT_FILES): {
|
||||
!equals(WASM_OBJECT_FILES, 1):!equals(WASM_OBJECT_FILES, 0): \
|
||||
message(Error: The value for WASM_OBJECT_FILES must be 0 or 1)
|
||||
QMAKE_CFLAGS += -s WASM_OBJECT_FILES=$$WASM_OBJECT_FILES
|
||||
QMAKE_CXXFLAGS += -s WASM_OBJECT_FILES=$$WASM_OBJECT_FILES
|
||||
QMAKE_LFLAGS += -s WASM_OBJECT_FILES=$$WASM_OBJECT_FILES
|
||||
}
|
||||
|
||||
EMTERP_FLAGS = \
|
||||
-s EMTERPRETIFY=1 \
|
||||
-s EMTERPRETIFY_ASYNC=1 \
|
||||
@ -22,10 +33,14 @@ EMCC_COMMON_LFLAGS = \
|
||||
-s \"BINARYEN_TRAP_MODE=\'clamp\'\"
|
||||
|
||||
EMCC_USE_PORTS_FLAGS = \
|
||||
-s USE_LIBPNG=1 \
|
||||
-s USE_FREETYPE=1 \
|
||||
-s USE_ZLIB=1
|
||||
|
||||
# libpng does not build for WASM_OBJECT_FILES=1, see
|
||||
# https://github.com/emscripten-core/emscripten/issues/8143
|
||||
equals(WASM_OBJECT_FILES, 0):\
|
||||
EMCC_USE_PORTS_FLAGS += -s USE_LIBPNG=1
|
||||
|
||||
# The -s arguments can also be used with release builds,
|
||||
# but are here in debug for clarity.
|
||||
EMCC_COMMON_LFLAGS_DEBUG = \
|
||||
@ -38,6 +53,35 @@ EMCC_COMMON_LFLAGS_DEBUG = \
|
||||
# -s SOCKET_DEBUG \ #print out socket,network data transfer
|
||||
-s GL_DEBUG=1
|
||||
|
||||
# Set up debug/optimization flags
|
||||
QMAKE_CXXFLAGS_RELEASE -= -O2
|
||||
QMAKE_CFLAGS_RELEASE -= -O2
|
||||
equals(WASM_OBJECT_FILES, 1) {
|
||||
QMAKE_LFLAGS_DEBUG += -g
|
||||
|
||||
QMAKE_CXXFLAGS_RELEASE += -O3
|
||||
QMAKE_CFLAGS_RELEASE += -O3
|
||||
QMAKE_LFLAGS_RELEASE += -O3
|
||||
QMAKE_CFLAGS_OPTIMIZE += -O3
|
||||
QMAKE_CFLAGS_OPTIMIZE_FULL += -Oz
|
||||
} else {
|
||||
# Practical debugging setup:
|
||||
# "-g4" preserves function names for stack traces
|
||||
# "-Os" produces reasonably sized binaries
|
||||
QMAKE_CFLAGS_DEBUG -= -g
|
||||
QMAKE_CXXFLAGS_DEBUG -= -g
|
||||
QMAKE_CFLAGS_DEBUG += -Os -g4
|
||||
QMAKE_CXXFLAGS_DEBUG += -Os -g4
|
||||
QMAKE_LFLAGS_DEBUG += -Os -g4
|
||||
|
||||
QMAKE_CXXFLAGS_RELEASE += -O3
|
||||
QMAKE_CFLAGS_RELEASE += -O3
|
||||
QMAKE_LFLAGS_RELEASE += -O3
|
||||
QMAKE_CFLAGS_OPTIMIZE += -O3
|
||||
QMAKE_CFLAGS_OPTIMIZE_FULL += -Oz
|
||||
}
|
||||
|
||||
|
||||
QMAKE_COMPILER += emscripten
|
||||
|
||||
QMAKE_CC = emcc
|
||||
@ -46,23 +90,6 @@ QMAKE_CXX = em++
|
||||
QMAKE_CFLAGS += $$EMCC_USE_PORTS_FLAGS
|
||||
QMAKE_CXXFLAGS += $$EMCC_USE_PORTS_FLAGS
|
||||
|
||||
# Practical debugging setup:
|
||||
# "-g4" preserves function names for stack traces
|
||||
# "-Os" produces reasonably sized binaries
|
||||
QMAKE_CFLAGS_DEBUG -= -g
|
||||
QMAKE_CXXFLAGS_DEBUG -= -g
|
||||
QMAKE_CFLAGS_DEBUG += -Os -g4
|
||||
QMAKE_CXXFLAGS_DEBUG += -Os -g4
|
||||
QMAKE_LFLAGS_DEBUG += -Os -g4
|
||||
|
||||
QMAKE_CXXFLAGS_RELEASE -= -O2
|
||||
QMAKE_CXXFLAGS_RELEASE += -O3
|
||||
QMAKE_CFLAGS_RELEASE -= -O2
|
||||
QMAKE_CFLAGS_RELEASE += -O3
|
||||
QMAKE_LFLAGS_RELEASE += -O3
|
||||
QMAKE_CFLAGS_OPTIMIZE += -O3
|
||||
QMAKE_CFLAGS_OPTIMIZE_FULL += -Oz
|
||||
|
||||
QMAKE_LINK = $$QMAKE_CXX
|
||||
QMAKE_LINK_SHLIB = $$QMAKE_CXX
|
||||
QMAKE_LINK_C = $$QMAKE_CC
|
||||
|
@ -84,6 +84,7 @@ Win32MakefileGenerator::findLibraries(bool linkPrl, bool mergeLflags)
|
||||
if (impexts.isEmpty())
|
||||
impexts = project->values("QMAKE_EXTENSION_STATICLIB");
|
||||
QList<QMakeLocalFileName> dirs;
|
||||
int libidx = 0;
|
||||
for (const ProString &dlib : project->values("QMAKE_DEFAULT_LIBDIRS"))
|
||||
dirs.append(QMakeLocalFileName(dlib.toQString()));
|
||||
static const char * const lflags[] = { "LIBS", "LIBS_PRIVATE",
|
||||
@ -96,11 +97,12 @@ Win32MakefileGenerator::findLibraries(bool linkPrl, bool mergeLflags)
|
||||
LibFlagType type = parseLibFlag(opt, &arg);
|
||||
if (type == LibFlagPath) {
|
||||
QMakeLocalFileName lp(arg.toQString());
|
||||
if (dirs.contains(lp)) {
|
||||
int idx = dirs.indexOf(lp);
|
||||
if (idx >= 0 && idx < libidx) {
|
||||
it = l.erase(it);
|
||||
continue;
|
||||
}
|
||||
dirs.append(lp);
|
||||
dirs.insert(libidx++, lp);
|
||||
(*it) = "-L" + lp.real();
|
||||
} else if (type == LibFlagLib) {
|
||||
QString lib = arg.toQString();
|
||||
|
@ -82,6 +82,7 @@ import android.view.inputmethod.InputMethodManager;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.PopupMenu;
|
||||
import android.hardware.display.DisplayManager;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.DataOutputStream;
|
||||
@ -667,6 +668,28 @@ public class QtActivityDelegate
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
DisplayManager.DisplayListener displayListener = new DisplayManager.DisplayListener() {
|
||||
@Override
|
||||
public void onDisplayAdded(int displayId) { }
|
||||
|
||||
@Override
|
||||
public void onDisplayChanged(int displayId) {
|
||||
m_currentRotation = m_activity.getWindowManager().getDefaultDisplay().getRotation();
|
||||
QtNative.handleOrientationChanged(m_currentRotation, m_nativeOrientation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisplayRemoved(int displayId) { }
|
||||
};
|
||||
|
||||
try {
|
||||
DisplayManager displayManager = (DisplayManager) m_activity.getSystemService(Context.DISPLAY_SERVICE);
|
||||
displayManager.registerDisplayListener(displayListener, null);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
m_mainLib = QtNative.loadMainLibrary(m_mainLib, nativeLibsDir);
|
||||
return m_mainLib != null;
|
||||
}
|
||||
@ -856,13 +879,6 @@ public class QtActivityDelegate
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
int rotation = m_activity.getWindowManager().getDefaultDisplay().getRotation();
|
||||
if (rotation != m_currentRotation) {
|
||||
QtNative.handleOrientationChanged(rotation, m_nativeOrientation);
|
||||
}
|
||||
|
||||
m_currentRotation = rotation;
|
||||
}
|
||||
|
||||
public void onDestroy()
|
||||
|
@ -286,7 +286,7 @@ static inline QStringList *resourceSearchPaths()
|
||||
decompress, use the \c{ZSTD_decompress} function from the zstd
|
||||
library.
|
||||
|
||||
\sa compressionAlgorithm(), isCopressed()
|
||||
\sa compressionAlgorithm(), isCompressed()
|
||||
*/
|
||||
|
||||
class QResourcePrivate {
|
||||
@ -558,7 +558,7 @@ bool QResource::isValid() const
|
||||
check compressionAlgorithm() to verify what algorithm to use to decompress
|
||||
the data.
|
||||
|
||||
\sa data(), compressionType(), isFile()
|
||||
\sa data(), compressionAlgorithm(), isFile()
|
||||
*/
|
||||
|
||||
bool QResource::isCompressed() const
|
||||
|
@ -912,16 +912,20 @@ QTemporaryFile *QTemporaryFile::createNativeFile(QFile &file)
|
||||
file.open(QIODevice::ReadOnly);
|
||||
//dump data
|
||||
QTemporaryFile *ret = new QTemporaryFile;
|
||||
ret->open();
|
||||
file.seek(0);
|
||||
char buffer[1024];
|
||||
while(true) {
|
||||
qint64 len = file.read(buffer, 1024);
|
||||
if(len < 1)
|
||||
break;
|
||||
ret->write(buffer, len);
|
||||
if (ret->open()) {
|
||||
file.seek(0);
|
||||
char buffer[1024];
|
||||
while (true) {
|
||||
qint64 len = file.read(buffer, 1024);
|
||||
if (len < 1)
|
||||
break;
|
||||
ret->write(buffer, len);
|
||||
}
|
||||
ret->seek(0);
|
||||
} else {
|
||||
delete ret;
|
||||
ret = nullptr;
|
||||
}
|
||||
ret->seek(0);
|
||||
//restore
|
||||
if(wasOpen)
|
||||
file.seek(old_off);
|
||||
|
@ -103,7 +103,7 @@ QConcatenateTablesProxyModelPrivate::QConcatenateTablesProxyModelPrivate()
|
||||
\since 5.13
|
||||
\class QConcatenateTablesProxyModel
|
||||
\inmodule QtCore
|
||||
\brief The QConcatenateTablesProxyModel class proxies multiple source models, concatenating their rows
|
||||
\brief The QConcatenateTablesProxyModel class proxies multiple source models, concatenating their rows.
|
||||
|
||||
\ingroup model-view
|
||||
|
||||
@ -163,7 +163,7 @@ QModelIndex QConcatenateTablesProxyModel::mapFromSource(const QModelIndex &sourc
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the source index for a given proxy index.
|
||||
Returns the source index for a given \a proxyIndex.
|
||||
*/
|
||||
QModelIndex QConcatenateTablesProxyModel::mapToSource(const QModelIndex &proxyIndex) const
|
||||
{
|
||||
@ -232,8 +232,8 @@ bool QConcatenateTablesProxyModel::setItemData(const QModelIndex &proxyIndex, co
|
||||
|
||||
/*!
|
||||
Returns the flags for the given index.
|
||||
If the index is valid, the flags come from the source model for this index.
|
||||
If the index is invalid (as used to determine if dropping onto an empty area
|
||||
If the \a index is valid, the flags come from the source model for this \a index.
|
||||
If the \a index is invalid (as used to determine if dropping onto an empty area
|
||||
in the view is allowed, for instance), the flags from the first model are returned.
|
||||
*/
|
||||
Qt::ItemFlags QConcatenateTablesProxyModel::flags(const QModelIndex &index) const
|
||||
|
@ -162,8 +162,9 @@ void QTransposeProxyModelPrivate::onRowsAboutToBeMoved(const QModelIndex &source
|
||||
/*!
|
||||
\since 5.13
|
||||
\class QTransposeProxyModel
|
||||
\brief This proxy transposes the source model
|
||||
\details This model will make the rows of the source model become columns of the proxy model and vice-versa.
|
||||
\brief This proxy transposes the source model.
|
||||
|
||||
This model will make the rows of the source model become columns of the proxy model and vice-versa.
|
||||
|
||||
If the model is a tree, the parents will be transposed as well. For example, if an index in the source model had parent `index(2,0)`, it will have parent `index(0,2)` in the proxy.
|
||||
*/
|
||||
|
@ -65,6 +65,19 @@ QCFString::operator CFStringRef() const
|
||||
|
||||
#if defined(QT_USE_APPLE_UNIFIED_LOGGING)
|
||||
|
||||
bool AppleUnifiedLogger::willMirrorToStderr()
|
||||
{
|
||||
// When running under Xcode or LLDB, one or more of these variables will
|
||||
// be set, which triggers libsystem_trace.dyld to log messages to stderr
|
||||
// as well, via_os_log_impl_mirror_to_stderr. Un-setting these variables
|
||||
// is not an option, as that would silence normal NSLog or os_log calls,
|
||||
// so instead we skip our own stderr output. See rdar://36919139.
|
||||
static bool willMirror = qEnvironmentVariableIsSet("OS_ACTIVITY_DT_MODE")
|
||||
|| qEnvironmentVariableIsSet("ACTIVITY_LOG_STDERR")
|
||||
|| qEnvironmentVariableIsSet("CFLOG_FORCE_STDERR");
|
||||
return willMirror;
|
||||
}
|
||||
|
||||
QT_MAC_WEAK_IMPORT(_os_log_default);
|
||||
bool AppleUnifiedLogger::messageHandler(QtMsgType msgType, const QMessageLogContext &context,
|
||||
const QString &message, const QString &optionalSubsystem)
|
||||
@ -103,15 +116,7 @@ bool AppleUnifiedLogger::messageHandler(QtMsgType msgType, const QMessageLogCont
|
||||
// system from redacting our log message.
|
||||
os_log_with_type(log, logType, "%{public}s", qPrintable(message));
|
||||
|
||||
// When running under Xcode or LLDB, one or more of these variables will
|
||||
// be set, which triggers libsystem_trace.dyld to log messages to stderr
|
||||
// as well, via_os_log_impl_mirror_to_stderr. Un-setting these variables
|
||||
// is not an option, as that would silence normal NSLog or os_log calls,
|
||||
// so instead we skip our own stderr output. See rdar://36919139.
|
||||
static bool mirroredToStderr = qEnvironmentVariableIsSet("OS_ACTIVITY_DT_MODE")
|
||||
|| qEnvironmentVariableIsSet("ACTIVITY_LOG_STDERR")
|
||||
|| qEnvironmentVariableIsSet("CFLOG_FORCE_STDERR");
|
||||
return mirroredToStderr;
|
||||
return willMirrorToStderr();
|
||||
}
|
||||
|
||||
os_log_type_t AppleUnifiedLogger::logTypeForMessageType(QtMsgType msgType)
|
||||
|
@ -202,6 +202,7 @@ class Q_CORE_EXPORT AppleUnifiedLogger
|
||||
public:
|
||||
static bool messageHandler(QtMsgType msgType, const QMessageLogContext &context, const QString &message,
|
||||
const QString &subsystem = QString());
|
||||
static bool willMirrorToStderr();
|
||||
private:
|
||||
static os_log_type_t logTypeForMessageType(QtMsgType msgType);
|
||||
static os_log_t cachedLog(const QString &subsystem, const QString &category);
|
||||
|
@ -178,7 +178,7 @@ public:
|
||||
#ifndef QT_NO_REGEXP
|
||||
#if QT_DEPRECATED_SINCE(5, 13)
|
||||
template<typename T>
|
||||
QT_DEPRECATED_X("Use findChildren(const RegularExpression &, ...) instead.")
|
||||
QT_DEPRECATED_X("Use findChildren(const QRegularExpression &, ...) instead.")
|
||||
inline QList<T> findChildren(const QRegExp &re, Qt::FindChildOptions options = Qt::FindChildrenRecursively) const
|
||||
{
|
||||
typedef typename std::remove_cv<typename std::remove_pointer<T>::type>::type ObjType;
|
||||
|
@ -818,6 +818,16 @@ void QThread::quit()
|
||||
|
||||
}
|
||||
|
||||
void QThread::exit(int returnCode)
|
||||
{
|
||||
Q_D(QThread);
|
||||
d->data->quitNow = true;
|
||||
for (int i = 0; i < d->data->eventLoops.size(); ++i) {
|
||||
QEventLoop *eventLoop = d->data->eventLoops.at(i);
|
||||
eventLoop->exit(returnCode);
|
||||
}
|
||||
}
|
||||
|
||||
bool QThread::wait(unsigned long time)
|
||||
{
|
||||
Q_UNUSED(time);
|
||||
|
@ -91,16 +91,29 @@ macro(_qt5gui_find_extra_libs Name Libs LibDir IncDirs)
|
||||
endforeach()
|
||||
!!ENDIF
|
||||
foreach(_lib ${Libs})
|
||||
string(REGEX REPLACE "[^_A-Za-z0-9]" "_" _cmake_lib_name ${_lib})
|
||||
if (IS_ABSOLUTE ${_lib})
|
||||
get_filename_component(_libFile ${_lib} NAME_WE)
|
||||
if (_libFile MATCHES \"^${CMAKE_SHARED_LIBRARY_PREFIX}(.*)\")
|
||||
set(_libFile ${CMAKE_MATCH_1})
|
||||
endif()
|
||||
else()
|
||||
set(_libFile ${_lib})
|
||||
endif()
|
||||
|
||||
string(REGEX REPLACE "[^_A-Za-z0-9]" "_" _cmake_lib_name ${_libFile})
|
||||
if (NOT TARGET Qt5::Gui_${_cmake_lib_name} AND NOT _Qt5Gui_${_cmake_lib_name}_LIBRARY_DONE)
|
||||
find_library(Qt5Gui_${_cmake_lib_name}_LIBRARY ${_lib}
|
||||
if (IS_ABSOLUTE ${_lib})
|
||||
set(Qt5Gui_${_cmake_lib_name}_LIBRARY ${_lib})
|
||||
else()
|
||||
find_library(Qt5Gui_${_cmake_lib_name}_LIBRARY ${_lib}
|
||||
!!IF !isEmpty(CROSS_COMPILE)
|
||||
PATHS \"${LibDir}\"
|
||||
PATHS \"${LibDir}\"
|
||||
!!IF !mac
|
||||
NO_DEFAULT_PATH
|
||||
NO_DEFAULT_PATH
|
||||
!!ENDIF
|
||||
!!ENDIF
|
||||
)
|
||||
)
|
||||
endif()
|
||||
!!IF mac
|
||||
set(Qt5Gui_${_cmake_lib_name}_LIBRARY "${Qt5Gui_${_cmake_lib_name}_LIBRARY}/${_lib}")
|
||||
if (NOT EXISTS "${Qt5Gui_${_cmake_lib_name}_LIBRARY}")
|
||||
|
@ -2259,16 +2259,16 @@ bool QImage::reinterpretAsFormat(Format format)
|
||||
\sa convertToFormat()
|
||||
*/
|
||||
|
||||
void QImage::convertTo(Format f, Qt::ImageConversionFlags flags)
|
||||
void QImage::convertTo(Format format, Qt::ImageConversionFlags flags)
|
||||
{
|
||||
if (!d || f == QImage::Format_Invalid)
|
||||
if (!d || format == QImage::Format_Invalid)
|
||||
return;
|
||||
|
||||
detach();
|
||||
if (convertToFormat_inplace(f, flags))
|
||||
if (convertToFormat_inplace(format, flags))
|
||||
return;
|
||||
|
||||
*this = convertToFormat_helper(f, flags);
|
||||
*this = convertToFormat_helper(format, flags);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -95,9 +95,9 @@ public:
|
||||
|
||||
void fill(const QColor &fillColor = Qt::white);
|
||||
#if QT_DEPRECATED_SINCE(5, 13)
|
||||
QT_DEPRECATED_X(" Use QPainter or the fill(QColor)")
|
||||
QT_DEPRECATED_X("Use QPainter or fill(QColor)")
|
||||
void fill(const QPaintDevice *device, const QPoint &ofs);
|
||||
QT_DEPRECATED_X(" Use QPainter or the fill(QColor)")
|
||||
QT_DEPRECATED_X("Use QPainter or fill(QColor)")
|
||||
void fill(const QPaintDevice *device, int xofs, int yofs);
|
||||
#endif
|
||||
|
||||
|
@ -114,6 +114,18 @@ qsizetype QOpenGLTextureUploader::textureImage(GLenum target, const QImage &imag
|
||||
externalFormat = GL_BGRA;
|
||||
internalFormat = GL_RGBA;
|
||||
pixelType = GL_UNSIGNED_INT_8_8_8_8_REV;
|
||||
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
|
||||
// Without GL_UNSIGNED_INT_8_8_8_8_REV, BGRA only matches ARGB on little endian:
|
||||
} else if (funcs->hasOpenGLExtension(QOpenGLExtensions::BGRATextureFormat) && !sRgbBinding) {
|
||||
// The GL_EXT_texture_format_BGRA8888 extension requires the internal format to match the external.
|
||||
externalFormat = internalFormat = GL_BGRA;
|
||||
pixelType = GL_UNSIGNED_BYTE;
|
||||
} else if (context->isOpenGLES() && context->hasExtension(QByteArrayLiteral("GL_APPLE_texture_format_BGRA8888"))) {
|
||||
// Is only allowed as an external format like OpenGL.
|
||||
externalFormat = GL_BGRA;
|
||||
internalFormat = GL_RGBA;
|
||||
pixelType = GL_UNSIGNED_BYTE;
|
||||
#endif
|
||||
} else if (funcs->hasOpenGLExtension(QOpenGLExtensions::TextureSwizzle)) {
|
||||
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
|
||||
GLint swizzle[4] = { GL_BLUE, GL_GREEN, GL_RED, GL_ALPHA };
|
||||
@ -125,25 +137,8 @@ qsizetype QOpenGLTextureUploader::textureImage(GLenum target, const QImage &imag
|
||||
externalFormat = internalFormat = GL_RGBA;
|
||||
pixelType = GL_UNSIGNED_BYTE;
|
||||
} else {
|
||||
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
|
||||
// Without GL_UNSIGNED_INT_8_8_8_8_REV, BGRA only matches ARGB on little endian.
|
||||
if (funcs->hasOpenGLExtension(QOpenGLExtensions::BGRATextureFormat) && !sRgbBinding) {
|
||||
// The GL_EXT_texture_format_BGRA8888 extension requires the internal format to match the external.
|
||||
externalFormat = internalFormat = GL_BGRA;
|
||||
pixelType = GL_UNSIGNED_BYTE;
|
||||
} else if (context->isOpenGLES() && context->hasExtension(QByteArrayLiteral("GL_APPLE_texture_format_BGRA8888"))) {
|
||||
// Is only allowed as an external format like OpenGL.
|
||||
externalFormat = GL_BGRA;
|
||||
internalFormat = GL_RGBA;
|
||||
pixelType = GL_UNSIGNED_BYTE;
|
||||
} else {
|
||||
// No support for direct ARGB32 upload.
|
||||
break;
|
||||
}
|
||||
#else
|
||||
// Big endian requires GL_UNSIGNED_INT_8_8_8_8_REV for ARGB to match BGRA
|
||||
// No support for direct ARGB32 upload.
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
targetFormat = image.format();
|
||||
break;
|
||||
|
@ -333,7 +333,9 @@ static ShiftResult shift(const QBezier *orig, QBezier *shifted, qreal offset, qr
|
||||
*shifted = QBezier::fromPoints(points_shifted[map[0]], points_shifted[map[1]],
|
||||
points_shifted[map[2]], points_shifted[map[3]]);
|
||||
|
||||
return good_offset(orig, shifted, offset, threshold);
|
||||
if (np > 2)
|
||||
return good_offset(orig, shifted, offset, threshold);
|
||||
return Ok;
|
||||
}
|
||||
|
||||
// This value is used to determine the length of control point vectors
|
||||
@ -432,7 +434,6 @@ redo:
|
||||
} else if (res == Ok) {
|
||||
++o;
|
||||
--b;
|
||||
continue;
|
||||
} else if (res == Circle && maxSegments - (o - curveSegments) >= 2) {
|
||||
// add semi circle
|
||||
if (addCircle(b, offset, o))
|
||||
|
@ -1421,7 +1421,7 @@ QTextCharFormat::QTextCharFormat(const QTextFormat &fmt)
|
||||
\fn void QTextCharFormat::setFontStyleName(const QString &styleName)
|
||||
\since 5.13
|
||||
|
||||
Sets the text format's font \a style name.
|
||||
Sets the text format's font \a styleName.
|
||||
|
||||
\sa setFont(), QFont::setStyleName()
|
||||
*/
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include <QtCore/qdebug.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
|
||||
@ -61,7 +62,7 @@ HeaderSize entry_size(const QByteArray &name, const QByteArray &value)
|
||||
// for counting the number of references to the name and value would have
|
||||
// 32 octets of overhead."
|
||||
|
||||
const unsigned sum = unsigned(name.size()) + value.size();
|
||||
const unsigned sum = unsigned(name.size() + value.size());
|
||||
if (std::numeric_limits<unsigned>::max() - 32 < sum)
|
||||
return HeaderSize();
|
||||
return HeaderSize(true, quint32(sum + 32));
|
||||
@ -75,7 +76,7 @@ int compare(const QByteArray &lhs, const QByteArray &rhs)
|
||||
if (const int minLen = std::min(lhs.size(), rhs.size())) {
|
||||
// We use memcmp, since strings in headers are allowed
|
||||
// to contain '\0'.
|
||||
const int cmp = std::memcmp(lhs.constData(), rhs.constData(), minLen);
|
||||
const int cmp = std::memcmp(lhs.constData(), rhs.constData(), std::size_t(minLen));
|
||||
if (cmp)
|
||||
return cmp;
|
||||
}
|
||||
@ -138,82 +139,6 @@ bool FieldLookupTable::SearchEntry::operator < (const SearchEntry &rhs)const
|
||||
return offset > rhs.offset;
|
||||
}
|
||||
|
||||
// This data is from HPACK's specs and it's quite
|
||||
// conveniently sorted == works with binary search as it is.
|
||||
// Later this can probably change and instead of simple
|
||||
// vector we'll just reuse FieldLookupTable.
|
||||
// TODO: it makes sense to generate this table while ...
|
||||
// configuring/building Qt (some script downloading/parsing/generating
|
||||
// would be quite handy).
|
||||
const std::vector<HeaderField> &staticTable()
|
||||
{
|
||||
static std::vector<HeaderField> table = {
|
||||
{":authority", ""},
|
||||
{":method", "GET"},
|
||||
{":method", "POST"},
|
||||
{":path", "/"},
|
||||
{":path", "/index.html"},
|
||||
{":scheme", "http"},
|
||||
{":scheme", "https"},
|
||||
{":status", "200"},
|
||||
{":status", "204"},
|
||||
{":status", "206"},
|
||||
{":status", "304"},
|
||||
{":status", "400"},
|
||||
{":status", "404"},
|
||||
{":status", "500"},
|
||||
{"accept-charset", ""},
|
||||
{"accept-encoding", "gzip, deflate"},
|
||||
{"accept-language", ""},
|
||||
{"accept-ranges", ""},
|
||||
{"accept", ""},
|
||||
{"access-control-allow-origin", ""},
|
||||
{"age", ""},
|
||||
{"allow", ""},
|
||||
{"authorization", ""},
|
||||
{"cache-control", ""},
|
||||
{"content-disposition", ""},
|
||||
{"content-encoding", ""},
|
||||
{"content-language", ""},
|
||||
{"content-length", ""},
|
||||
{"content-location", ""},
|
||||
{"content-range", ""},
|
||||
{"content-type", ""},
|
||||
{"cookie", ""},
|
||||
{"date", ""},
|
||||
{"etag", ""},
|
||||
{"expect", ""},
|
||||
{"expires", ""},
|
||||
{"from", ""},
|
||||
{"host", ""},
|
||||
{"if-match", ""},
|
||||
{"if-modified-since", ""},
|
||||
{"if-none-match", ""},
|
||||
{"if-range", ""},
|
||||
{"if-unmodified-since", ""},
|
||||
{"last-modified", ""},
|
||||
{"link", ""},
|
||||
{"location", ""},
|
||||
{"max-forwards", ""},
|
||||
{"proxy-authenticate", ""},
|
||||
{"proxy-authorization", ""},
|
||||
{"range", ""},
|
||||
{"referer", ""},
|
||||
{"refresh", ""},
|
||||
{"retry-after", ""},
|
||||
{"server", ""},
|
||||
{"set-cookie", ""},
|
||||
{"strict-transport-security", ""},
|
||||
{"transfer-encoding", ""},
|
||||
{"user-agent", ""},
|
||||
{"vary", ""},
|
||||
{"via", ""},
|
||||
{"www-authenticate", ""}
|
||||
};
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
FieldLookupTable::FieldLookupTable(quint32 maxSize, bool use)
|
||||
: maxTableSize(maxSize),
|
||||
tableCapacity(maxSize),
|
||||
@ -296,12 +221,12 @@ void FieldLookupTable::evictEntry()
|
||||
|
||||
quint32 FieldLookupTable::numberOfEntries() const
|
||||
{
|
||||
return quint32(staticTable().size()) + nDynamic;
|
||||
return quint32(staticPart().size()) + nDynamic;
|
||||
}
|
||||
|
||||
quint32 FieldLookupTable::numberOfStaticEntries() const
|
||||
{
|
||||
return quint32(staticTable().size());
|
||||
return quint32(staticPart().size());
|
||||
}
|
||||
|
||||
quint32 FieldLookupTable::numberOfDynamicEntries() const
|
||||
@ -326,24 +251,18 @@ void FieldLookupTable::clearDynamicTable()
|
||||
|
||||
bool FieldLookupTable::indexIsValid(quint32 index) const
|
||||
{
|
||||
return index && index <= staticTable().size() + nDynamic;
|
||||
return index && index <= staticPart().size() + nDynamic;
|
||||
}
|
||||
|
||||
quint32 FieldLookupTable::indexOf(const QByteArray &name, const QByteArray &value)const
|
||||
{
|
||||
// Start from the static part first:
|
||||
const auto &table = staticTable();
|
||||
const auto &table = staticPart();
|
||||
const HeaderField field(name, value);
|
||||
const auto staticPos = std::lower_bound(table.begin(), table.end(), field,
|
||||
[](const HeaderField &lhs, const HeaderField &rhs) {
|
||||
int cmp = compare(lhs.name, rhs.name);
|
||||
if (cmp)
|
||||
return cmp < 0;
|
||||
return compare(lhs.value, rhs.value) < 0;
|
||||
});
|
||||
const auto staticPos = findInStaticPart(field, CompareMode::nameAndValue);
|
||||
if (staticPos != table.end()) {
|
||||
if (staticPos->name == name && staticPos->value == value)
|
||||
return staticPos - table.begin() + 1;
|
||||
return quint32(staticPos - table.begin() + 1);
|
||||
}
|
||||
|
||||
// Now we have to lookup in our dynamic part ...
|
||||
@ -366,15 +285,12 @@ quint32 FieldLookupTable::indexOf(const QByteArray &name, const QByteArray &valu
|
||||
quint32 FieldLookupTable::indexOf(const QByteArray &name) const
|
||||
{
|
||||
// Start from the static part first:
|
||||
const auto &table = staticTable();
|
||||
const auto &table = staticPart();
|
||||
const HeaderField field(name, QByteArray());
|
||||
const auto staticPos = std::lower_bound(table.begin(), table.end(), field,
|
||||
[](const HeaderField &lhs, const HeaderField &rhs) {
|
||||
return compare(lhs.name, rhs.name) < 0;
|
||||
});
|
||||
const auto staticPos = findInStaticPart(field, CompareMode::nameOnly);
|
||||
if (staticPos != table.end()) {
|
||||
if (staticPos->name == name)
|
||||
return staticPos - table.begin() + 1;
|
||||
return quint32(staticPos - table.begin() + 1);
|
||||
}
|
||||
|
||||
// Now we have to lookup in our dynamic part ...
|
||||
@ -402,7 +318,7 @@ bool FieldLookupTable::field(quint32 index, QByteArray *name, QByteArray *value)
|
||||
if (!indexIsValid(index))
|
||||
return false;
|
||||
|
||||
const auto &table = staticTable();
|
||||
const auto &table = staticPart();
|
||||
if (index - 1 < table.size()) {
|
||||
*name = table[index - 1].name;
|
||||
*value = table[index - 1].value;
|
||||
@ -477,7 +393,7 @@ quint32 FieldLookupTable::keyToIndex(const SearchEntry &key) const
|
||||
Q_ASSERT(offset < ChunkSize);
|
||||
Q_ASSERT(chunkIndex || offset >= begin);
|
||||
|
||||
return quint32(offset + chunkIndex * ChunkSize - begin + 1 + staticTable().size());
|
||||
return quint32(offset + chunkIndex * ChunkSize - begin + 1 + staticPart().size());
|
||||
}
|
||||
|
||||
FieldLookupTable::SearchEntry FieldLookupTable::frontKey() const
|
||||
@ -526,6 +442,103 @@ void FieldLookupTable::setMaxDynamicTableSize(quint32 size)
|
||||
updateDynamicTableSize(size);
|
||||
}
|
||||
|
||||
// This data is from the HPACK's specs and it's quite conveniently sorted,
|
||||
// except ... 'accept' is in the wrong position, see how we handle it below.
|
||||
const std::vector<HeaderField> &FieldLookupTable::staticPart()
|
||||
{
|
||||
static std::vector<HeaderField> table = {
|
||||
{":authority", ""},
|
||||
{":method", "GET"},
|
||||
{":method", "POST"},
|
||||
{":path", "/"},
|
||||
{":path", "/index.html"},
|
||||
{":scheme", "http"},
|
||||
{":scheme", "https"},
|
||||
{":status", "200"},
|
||||
{":status", "204"},
|
||||
{":status", "206"},
|
||||
{":status", "304"},
|
||||
{":status", "400"},
|
||||
{":status", "404"},
|
||||
{":status", "500"},
|
||||
{"accept-charset", ""},
|
||||
{"accept-encoding", "gzip, deflate"},
|
||||
{"accept-language", ""},
|
||||
{"accept-ranges", ""},
|
||||
{"accept", ""},
|
||||
{"access-control-allow-origin", ""},
|
||||
{"age", ""},
|
||||
{"allow", ""},
|
||||
{"authorization", ""},
|
||||
{"cache-control", ""},
|
||||
{"content-disposition", ""},
|
||||
{"content-encoding", ""},
|
||||
{"content-language", ""},
|
||||
{"content-length", ""},
|
||||
{"content-location", ""},
|
||||
{"content-range", ""},
|
||||
{"content-type", ""},
|
||||
{"cookie", ""},
|
||||
{"date", ""},
|
||||
{"etag", ""},
|
||||
{"expect", ""},
|
||||
{"expires", ""},
|
||||
{"from", ""},
|
||||
{"host", ""},
|
||||
{"if-match", ""},
|
||||
{"if-modified-since", ""},
|
||||
{"if-none-match", ""},
|
||||
{"if-range", ""},
|
||||
{"if-unmodified-since", ""},
|
||||
{"last-modified", ""},
|
||||
{"link", ""},
|
||||
{"location", ""},
|
||||
{"max-forwards", ""},
|
||||
{"proxy-authenticate", ""},
|
||||
{"proxy-authorization", ""},
|
||||
{"range", ""},
|
||||
{"referer", ""},
|
||||
{"refresh", ""},
|
||||
{"retry-after", ""},
|
||||
{"server", ""},
|
||||
{"set-cookie", ""},
|
||||
{"strict-transport-security", ""},
|
||||
{"transfer-encoding", ""},
|
||||
{"user-agent", ""},
|
||||
{"vary", ""},
|
||||
{"via", ""},
|
||||
{"www-authenticate", ""}
|
||||
};
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
std::vector<HeaderField>::const_iterator FieldLookupTable::findInStaticPart(const HeaderField &field, CompareMode mode)
|
||||
{
|
||||
const auto &table = staticPart();
|
||||
const auto acceptPos = table.begin() + 18;
|
||||
if (field.name == "accept") {
|
||||
if (mode == CompareMode::nameAndValue && field.value != "")
|
||||
return table.end();
|
||||
return acceptPos;
|
||||
}
|
||||
|
||||
auto predicate = [mode](const HeaderField &lhs, const HeaderField &rhs) {
|
||||
const int cmp = compare(lhs.name, rhs.name);
|
||||
if (cmp)
|
||||
return cmp < 0;
|
||||
else if (mode == CompareMode::nameAndValue)
|
||||
return compare(lhs.value, rhs.value) < 0;
|
||||
return false;
|
||||
};
|
||||
|
||||
const auto staticPos = std::lower_bound(table.begin(), acceptPos, field, predicate);
|
||||
if (staticPos != acceptPos)
|
||||
return staticPos;
|
||||
|
||||
return std::lower_bound(acceptPos + 1, table.end(), field, predicate);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -173,6 +173,8 @@ public:
|
||||
bool updateDynamicTableSize(quint32 size);
|
||||
void setMaxDynamicTableSize(quint32 size);
|
||||
|
||||
static const std::vector<HeaderField> &staticPart();
|
||||
|
||||
private:
|
||||
// Table's maximum size is controlled
|
||||
// by SETTINGS_HEADER_TABLE_SIZE (HTTP/2, 6.5.2).
|
||||
@ -225,9 +227,16 @@ private:
|
||||
quint32 indexOfChunk(const Chunk *chunk) const;
|
||||
quint32 keyToIndex(const SearchEntry &key) const;
|
||||
|
||||
enum class CompareMode {
|
||||
nameOnly,
|
||||
nameAndValue
|
||||
};
|
||||
|
||||
static std::vector<HeaderField>::const_iterator findInStaticPart(const HeaderField &field, CompareMode mode);
|
||||
|
||||
mutable QByteArray dummyDst;
|
||||
|
||||
Q_DISABLE_COPY_MOVE(FieldLookupTable);
|
||||
Q_DISABLE_COPY_MOVE(FieldLookupTable)
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -265,7 +265,7 @@ qint64 QNetworkReplyWasmImpl::readData(char *data, qint64 maxlen)
|
||||
Q_D(QNetworkReplyWasmImpl);
|
||||
|
||||
qint64 howMuch = qMin(maxlen, (d->downloadBuffer.size() - d->downloadBufferReadPosition));
|
||||
memcpy(data, d->downloadBuffer.constData(), howMuch);
|
||||
memcpy(data, d->downloadBuffer.constData() + d->downloadBufferReadPosition, howMuch);
|
||||
d->downloadBufferReadPosition += howMuch;
|
||||
|
||||
return howMuch;
|
||||
|
@ -46,7 +46,7 @@ QT_BEGIN_NAMESPACE
|
||||
|
||||
/*!
|
||||
\class QOcspResponse
|
||||
\brief This class represents Online Certificate Status Protocol response
|
||||
\brief This class represents Online Certificate Status Protocol response.
|
||||
\since 5.13
|
||||
|
||||
\ingroup network
|
||||
@ -57,7 +57,7 @@ QT_BEGIN_NAMESPACE
|
||||
received by the client-side socket during the TLS handshake. QSslSocket must be
|
||||
configured with OCSP stapling enabled.
|
||||
|
||||
\sa QSslSocket, QSslSocket::ocspResponse(), certificateStatus(),
|
||||
\sa QSslSocket, QSslSocket::ocspResponses(), certificateStatus(),
|
||||
revocationReason(), responder(), subject(), QOcspCertificateStatus, QOcspRevocationReason,
|
||||
QSslConfiguration::setOcspStaplingEnabled(), QSslConfiguration::ocspStaplingEnabled(),
|
||||
QSslConfiguration::peerCertificate()
|
||||
@ -126,14 +126,14 @@ QOcspResponse::QOcspResponse()
|
||||
|
||||
Creates a new response, the copy of \a other.
|
||||
*/
|
||||
QOcspResponse::QOcspResponse(const QOcspResponse &other) = default;
|
||||
QOcspResponse::QOcspResponse(const QOcspResponse &) = default;
|
||||
|
||||
/*!
|
||||
\since 5.13
|
||||
|
||||
Move-constructs a QOcspResponse instance from \a other.
|
||||
*/
|
||||
QOcspResponse::QOcspResponse(QOcspResponse &&other) Q_DECL_NOTHROW = default;
|
||||
QOcspResponse::QOcspResponse(QOcspResponse &&) Q_DECL_NOTHROW = default;
|
||||
|
||||
/*!
|
||||
\since 5.13
|
||||
@ -147,14 +147,14 @@ QOcspResponse::~QOcspResponse() = default;
|
||||
|
||||
Assigns \a other to the response and returns a reference to this response.
|
||||
*/
|
||||
QOcspResponse &QOcspResponse::operator=(const QOcspResponse &other) = default;
|
||||
QOcspResponse &QOcspResponse::operator=(const QOcspResponse &) = default;
|
||||
|
||||
/*!
|
||||
\since 5.13
|
||||
|
||||
Move-assigns \a other to this QOcspResponse instance.
|
||||
*/
|
||||
QOcspResponse &QOcspResponse::operator=(QOcspResponse &&other) Q_DECL_NOTHROW = default;
|
||||
QOcspResponse &QOcspResponse::operator=(QOcspResponse &&) Q_DECL_NOTHROW = default;
|
||||
|
||||
/*!
|
||||
\fn void QOcspResponse::swap(QOcspResponse &other)
|
||||
|
@ -179,7 +179,15 @@ static inline bool checkNeedPortalSupport()
|
||||
return !QStandardPaths::locate(QStandardPaths::RuntimeLocation, QLatin1String("flatpak-info")).isEmpty() || qEnvironmentVariableIsSet("SNAP");
|
||||
}
|
||||
|
||||
static inline bool xdgDesktopPortalOpenFile(const QUrl &url)
|
||||
static inline bool isPortalReturnPermanent(const QDBusError &error)
|
||||
{
|
||||
// A service unknown error isn't permanent, it just indicates that we
|
||||
// should fall back to the regular way. This check includes
|
||||
// QDBusError::NoError.
|
||||
return error.type() != QDBusError::ServiceUnknown;
|
||||
}
|
||||
|
||||
static inline QDBusMessage xdgDesktopPortalOpenFile(const QUrl &url)
|
||||
{
|
||||
// DBus signature:
|
||||
// OpenFile (IN s parent_window,
|
||||
@ -198,23 +206,22 @@ static inline bool xdgDesktopPortalOpenFile(const QUrl &url)
|
||||
QLatin1String("org.freedesktop.portal.OpenURI"),
|
||||
QLatin1String("OpenFile"));
|
||||
|
||||
QDBusUnixFileDescriptor descriptor(fd);
|
||||
qt_safe_close(fd);
|
||||
QDBusUnixFileDescriptor descriptor;
|
||||
descriptor.giveFileDescriptor(fd);
|
||||
|
||||
// FIXME parent_window_id and handle writable option
|
||||
message << QString() << QVariant::fromValue(descriptor) << QVariantMap();
|
||||
|
||||
QDBusPendingReply<QDBusObjectPath> reply = QDBusConnection::sessionBus().call(message);
|
||||
return !reply.isError();
|
||||
return QDBusConnection::sessionBus().call(message);
|
||||
}
|
||||
#else
|
||||
Q_UNUSED(url)
|
||||
#endif
|
||||
|
||||
return false;
|
||||
return QDBusMessage::createError(QDBusError::InternalError, qt_error_string());
|
||||
}
|
||||
|
||||
static inline bool xdgDesktopPortalOpenUrl(const QUrl &url)
|
||||
static inline QDBusMessage xdgDesktopPortalOpenUrl(const QUrl &url)
|
||||
{
|
||||
// DBus signature:
|
||||
// OpenURI (IN s parent_window,
|
||||
@ -234,11 +241,10 @@ static inline bool xdgDesktopPortalOpenUrl(const QUrl &url)
|
||||
// FIXME parent_window_id and handle writable option
|
||||
message << QString() << url.toString() << QVariantMap();
|
||||
|
||||
QDBusPendingReply<QDBusObjectPath> reply = QDBusConnection::sessionBus().call(message);
|
||||
return !reply.isError();
|
||||
return QDBusConnection::sessionBus().call(message);
|
||||
}
|
||||
|
||||
static inline bool xdgDesktopPortalSendEmail(const QUrl &url)
|
||||
static inline QDBusMessage xdgDesktopPortalSendEmail(const QUrl &url)
|
||||
{
|
||||
// DBus signature:
|
||||
// ComposeEmail (IN s parent_window,
|
||||
@ -281,8 +287,7 @@ static inline bool xdgDesktopPortalSendEmail(const QUrl &url)
|
||||
// FIXME parent_window_id
|
||||
message << QString() << options;
|
||||
|
||||
QDBusPendingReply<QDBusObjectPath> reply = QDBusConnection::sessionBus().call(message);
|
||||
return !reply.isError();
|
||||
return QDBusConnection::sessionBus().call(message);
|
||||
}
|
||||
#endif // QT_CONFIG(dbus)
|
||||
|
||||
@ -296,15 +301,23 @@ bool QGenericUnixServices::openUrl(const QUrl &url)
|
||||
{
|
||||
if (url.scheme() == QLatin1String("mailto")) {
|
||||
#if QT_CONFIG(dbus)
|
||||
if (checkNeedPortalSupport())
|
||||
return xdgDesktopPortalSendEmail(url);
|
||||
if (checkNeedPortalSupport()) {
|
||||
QDBusError error = xdgDesktopPortalSendEmail(url);
|
||||
if (isPortalReturnPermanent(error))
|
||||
return !error.isValid();
|
||||
|
||||
// service not running, fall back
|
||||
}
|
||||
#endif
|
||||
return openDocument(url);
|
||||
}
|
||||
|
||||
#if QT_CONFIG(dbus)
|
||||
if (checkNeedPortalSupport())
|
||||
return xdgDesktopPortalOpenUrl(url);
|
||||
if (checkNeedPortalSupport()) {
|
||||
QDBusError error = xdgDesktopPortalOpenUrl(url);
|
||||
if (isPortalReturnPermanent(error))
|
||||
return !error.isValid();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m_webBrowser.isEmpty() && !detectWebBrowser(desktopEnvironment(), true, &m_webBrowser)) {
|
||||
@ -317,8 +330,11 @@ bool QGenericUnixServices::openUrl(const QUrl &url)
|
||||
bool QGenericUnixServices::openDocument(const QUrl &url)
|
||||
{
|
||||
#if QT_CONFIG(dbus)
|
||||
if (checkNeedPortalSupport())
|
||||
return xdgDesktopPortalOpenFile(url);
|
||||
if (checkNeedPortalSupport()) {
|
||||
QDBusError error = xdgDesktopPortalOpenFile(url);
|
||||
if (isPortalReturnPermanent(error))
|
||||
return !error.isValid();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (m_documentLauncher.isEmpty() && !detectWebBrowser(desktopEnvironment(), false, &m_documentLauncher)) {
|
||||
|
@ -70,7 +70,9 @@ void QComposeInputContext::ensureInitialized()
|
||||
}
|
||||
|
||||
m_initialized = true;
|
||||
const char *const locale = setlocale(LC_CTYPE, "");
|
||||
const char *locale = setlocale(LC_CTYPE, "");
|
||||
if (!locale)
|
||||
locale = setlocale(LC_CTYPE, nullptr);
|
||||
qCDebug(lcXkbCompose) << "detected locale (LC_CTYPE):" << locale;
|
||||
|
||||
m_composeTable = xkb_compose_table_new_from_locale(m_XkbContext, locale, XKB_COMPOSE_COMPILE_NO_FLAGS);
|
||||
|
@ -62,7 +62,7 @@ QT_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcQpaWindow, "qt.qpa.window");
|
||||
Q_LOGGING_CATEGORY(lcQpaDrawing, "qt.qpa.drawing");
|
||||
Q_LOGGING_CATEGORY(lcQpaMouse, "qt.qpa.input.mouse");
|
||||
Q_LOGGING_CATEGORY(lcQpaMouse, "qt.qpa.input.mouse", QtCriticalMsg);
|
||||
Q_LOGGING_CATEGORY(lcQpaScreen, "qt.qpa.screen");
|
||||
|
||||
//
|
||||
|
@ -137,22 +137,13 @@
|
||||
{
|
||||
if ((self = [super initWithFrame:NSZeroRect])) {
|
||||
m_platformWindow = platformWindow;
|
||||
m_buttons = Qt::NoButton;
|
||||
m_acceptedMouseDowns = Qt::NoButton;
|
||||
m_frameStrutButtons = Qt::NoButton;
|
||||
m_sendKeyEvent = false;
|
||||
m_sendUpAsRightButton = false;
|
||||
m_inputSource = nil;
|
||||
m_mouseMoveHelper = [[QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper) alloc] initWithView:self];
|
||||
m_resendKeyEvent = false;
|
||||
m_scrolling = false;
|
||||
m_updatingDrag = false;
|
||||
m_currentlyInterpretedKeyEvent = nil;
|
||||
m_dontOverrideCtrlLMB = qt_mac_resolveOption(false, platformWindow->window(),
|
||||
"_q_platform_MacDontOverrideCtrlLMB", "QT_MAC_DONT_OVERRIDE_CTRL_LMB");
|
||||
|
||||
self.focusRingType = NSFocusRingTypeNone;
|
||||
self.cursor = nil;
|
||||
|
||||
self.previousSuperview = nil;
|
||||
self.previousWindow = nil;
|
||||
|
@ -57,9 +57,9 @@
|
||||
NSFilesPromisePboardType, NSInkTextPboardType,
|
||||
NSMultipleTextSelectionPboardType, mimeTypeGeneric]];
|
||||
|
||||
// Add custom types supported by the application.
|
||||
// Add custom types supported by the application
|
||||
for (const QString &customType : qt_mac_enabledDraggedTypes())
|
||||
[supportedTypes addObject:customType.toNSString()];
|
||||
[supportedTypes addObject:customType.toNSString()];
|
||||
|
||||
[self registerForDraggedTypes:supportedTypes];
|
||||
}
|
||||
@ -79,11 +79,11 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin
|
||||
return target->mapFromGlobal(source->mapToGlobal(point));
|
||||
}
|
||||
|
||||
- (NSDragOperation)draggingSession:(NSDraggingSession *)session
|
||||
sourceOperationMaskForDraggingContext:(NSDraggingContext)context
|
||||
- (NSDragOperation)draggingSession:(NSDraggingSession *)session sourceOperationMaskForDraggingContext:(NSDraggingContext)context
|
||||
{
|
||||
Q_UNUSED(session);
|
||||
Q_UNUSED(context);
|
||||
|
||||
QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
|
||||
return qt_mac_mapDropActions(nativeDrag->currentDrag()->supportedActions());
|
||||
}
|
||||
@ -134,30 +134,29 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin
|
||||
|
||||
if (pixmapCursor.isNull()) {
|
||||
switch (response.acceptedAction()) {
|
||||
case Qt::CopyAction:
|
||||
nativeCursor = [NSCursor dragCopyCursor];
|
||||
break;
|
||||
case Qt::LinkAction:
|
||||
nativeCursor = [NSCursor dragLinkCursor];
|
||||
break;
|
||||
case Qt::IgnoreAction:
|
||||
// Uncomment the next lines if forbiden cursor wanted on non droppable targets.
|
||||
/*nativeCursor = [NSCursor operationNotAllowedCursor];
|
||||
break;*/
|
||||
case Qt::MoveAction:
|
||||
default:
|
||||
nativeCursor = [NSCursor arrowCursor];
|
||||
break;
|
||||
case Qt::CopyAction:
|
||||
nativeCursor = [NSCursor dragCopyCursor];
|
||||
break;
|
||||
case Qt::LinkAction:
|
||||
nativeCursor = [NSCursor dragLinkCursor];
|
||||
break;
|
||||
case Qt::IgnoreAction:
|
||||
// Uncomment the next lines if forbidden cursor is wanted on undroppable targets.
|
||||
/*nativeCursor = [NSCursor operationNotAllowedCursor];
|
||||
break;*/
|
||||
case Qt::MoveAction:
|
||||
default:
|
||||
nativeCursor = [NSCursor arrowCursor];
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
NSImage *nsimage = qt_mac_create_nsimage(pixmapCursor);
|
||||
nsimage.size = NSSizeFromCGSize((pixmapCursor.size() / pixmapCursor.devicePixelRatioF()).toCGSize());
|
||||
nativeCursor = [[NSCursor alloc] initWithImage:nsimage hotSpot:NSZeroPoint];
|
||||
[nsimage release];
|
||||
}
|
||||
|
||||
// change the cursor
|
||||
// Change the cursor
|
||||
[nativeCursor set];
|
||||
|
||||
// Make sure the cursor is updated correctly if the mouse does not move and window is under cursor
|
||||
@ -169,39 +168,33 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin
|
||||
if (m_updatingDrag)
|
||||
return;
|
||||
|
||||
const QPoint mousePos(QCursor::pos());
|
||||
CGEventRef moveEvent(CGEventCreateMouseEvent(
|
||||
NULL, kCGEventMouseMoved,
|
||||
CGPointMake(mousePos.x(), mousePos.y()),
|
||||
QCFType<CGEventRef> moveEvent = CGEventCreateMouseEvent(
|
||||
nullptr, kCGEventMouseMoved, QCursor::pos().toCGPoint(),
|
||||
kCGMouseButtonLeft // ignored
|
||||
));
|
||||
);
|
||||
CGEventPost(kCGHIDEventTap, moveEvent);
|
||||
CFRelease(moveEvent);
|
||||
}
|
||||
|
||||
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
|
||||
- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender
|
||||
{
|
||||
return [self handleDrag : sender];
|
||||
return [self handleDrag:(QEvent::DragEnter) sender:sender];
|
||||
}
|
||||
|
||||
- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
|
||||
- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender
|
||||
{
|
||||
m_updatingDrag = true;
|
||||
const NSDragOperation ret([self handleDrag : sender]);
|
||||
m_updatingDrag = false;
|
||||
|
||||
return ret;
|
||||
QScopedValueRollback<bool> rollback(m_updatingDrag, true);
|
||||
return [self handleDrag:(QEvent::DragMove) sender:sender];
|
||||
}
|
||||
|
||||
// Sends drag update to Qt, return the action
|
||||
- (NSDragOperation)handleDrag:(id <NSDraggingInfo>)sender
|
||||
- (NSDragOperation)handleDrag:(QEvent::Type)dragType sender:(id<NSDraggingInfo>)sender
|
||||
{
|
||||
if (!m_platformWindow)
|
||||
return NSDragOperationNone;
|
||||
|
||||
NSPoint windowPoint = [self convertPoint: [sender draggingLocation] fromView: nil];
|
||||
QPoint qt_windowPoint(windowPoint.x, windowPoint.y);
|
||||
Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations([sender draggingSourceOperationMask]);
|
||||
QPoint windowPoint = QPointF::fromCGPoint([self convertPoint:sender.draggingLocation fromView:nil]).toPoint();
|
||||
|
||||
Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations(sender.draggingSourceOperationMask);
|
||||
|
||||
QWindow *target = findEventTargetWindow(m_platformWindow->window());
|
||||
if (!target)
|
||||
@ -209,7 +202,12 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin
|
||||
|
||||
const auto modifiers = [QNSView convertKeyModifiers:NSApp.currentEvent.modifierFlags];
|
||||
const auto buttons = currentlyPressedMouseButtons();
|
||||
const auto point = mapWindowCoordinates(m_platformWindow->window(), target, qt_windowPoint);
|
||||
const auto point = mapWindowCoordinates(m_platformWindow->window(), target, windowPoint);
|
||||
|
||||
if (dragType == QEvent::DragEnter)
|
||||
qCDebug(lcQpaMouse) << dragType << self << "at" << windowPoint;
|
||||
else
|
||||
qCDebug(lcQpaMouse) << dragType << "at" << windowPoint << "with" << buttons;
|
||||
|
||||
QPlatformDragQtResponse response(false, Qt::IgnoreAction, QRect());
|
||||
QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
|
||||
@ -219,7 +217,7 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin
|
||||
point, qtAllowed, buttons, modifiers);
|
||||
[self updateCursorFromDragResponse:response drag:nativeDrag];
|
||||
} else {
|
||||
QCocoaDropData mimeData([sender draggingPasteboard]);
|
||||
QCocoaDropData mimeData(sender.draggingPasteboard);
|
||||
response = QWindowSystemInterface::handleDrag(target, &mimeData,
|
||||
point, qtAllowed, buttons, modifiers);
|
||||
}
|
||||
@ -227,7 +225,7 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin
|
||||
return qt_mac_mapDropAction(response.acceptedAction());
|
||||
}
|
||||
|
||||
- (void)draggingExited:(id <NSDraggingInfo>)sender
|
||||
- (void)draggingExited:(id<NSDraggingInfo>)sender
|
||||
{
|
||||
if (!m_platformWindow)
|
||||
return;
|
||||
@ -236,17 +234,18 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
NSPoint windowPoint = [self convertPoint: [sender draggingLocation] fromView: nil];
|
||||
QPoint qt_windowPoint(windowPoint.x, windowPoint.y);
|
||||
QPoint windowPoint = QPointF::fromCGPoint([self convertPoint:sender.draggingLocation fromView:nil]).toPoint();
|
||||
|
||||
qCDebug(lcQpaMouse) << QEvent::DragLeave << self << "at" << windowPoint;
|
||||
|
||||
// Send 0 mime data to indicate drag exit
|
||||
QWindowSystemInterface::handleDrag(target, nullptr,
|
||||
mapWindowCoordinates(m_platformWindow->window(), target, qt_windowPoint),
|
||||
mapWindowCoordinates(m_platformWindow->window(), target, windowPoint),
|
||||
Qt::IgnoreAction, Qt::NoButton, Qt::NoModifier);
|
||||
}
|
||||
|
||||
// called on drop, send the drop to Qt and return if it was accepted.
|
||||
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
|
||||
// Called on drop, send the drop to Qt and return if it was accepted
|
||||
- (BOOL)performDragOperation:(id<NSDraggingInfo>)sender
|
||||
{
|
||||
if (!m_platformWindow)
|
||||
return false;
|
||||
@ -255,31 +254,31 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin
|
||||
if (!target)
|
||||
return false;
|
||||
|
||||
NSPoint windowPoint = [self convertPoint: [sender draggingLocation] fromView: nil];
|
||||
QPoint qt_windowPoint(windowPoint.x, windowPoint.y);
|
||||
Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations([sender draggingSourceOperationMask]);
|
||||
QPoint windowPoint = QPointF::fromCGPoint([self convertPoint:sender.draggingLocation fromView:nil]).toPoint();
|
||||
|
||||
Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations(sender.draggingSourceOperationMask);
|
||||
|
||||
QPlatformDropQtResponse response(false, Qt::IgnoreAction);
|
||||
QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag();
|
||||
const auto modifiers = [QNSView convertKeyModifiers:NSApp.currentEvent.modifierFlags];
|
||||
const auto buttons = currentlyPressedMouseButtons();
|
||||
const auto point = mapWindowCoordinates(m_platformWindow->window(), target, qt_windowPoint);
|
||||
const auto point = mapWindowCoordinates(m_platformWindow->window(), target, windowPoint);
|
||||
|
||||
qCDebug(lcQpaMouse) << QEvent::Drop << "at" << windowPoint << "with" << buttons;
|
||||
|
||||
if (nativeDrag->currentDrag()) {
|
||||
// The drag was started from within the application
|
||||
response = QWindowSystemInterface::handleDrop(target, nativeDrag->dragMimeData(),
|
||||
point, qtAllowed, buttons, modifiers);
|
||||
} else {
|
||||
QCocoaDropData mimeData([sender draggingPasteboard]);
|
||||
QCocoaDropData mimeData(sender.draggingPasteboard);
|
||||
response = QWindowSystemInterface::handleDrop(target, &mimeData,
|
||||
point, qtAllowed, buttons, modifiers);
|
||||
}
|
||||
return response.isAccepted();
|
||||
}
|
||||
|
||||
- (void)draggingSession:(NSDraggingSession *)session
|
||||
endedAtPoint:(NSPoint)screenPoint
|
||||
operation:(NSDragOperation)operation
|
||||
- (void)draggingSession:(NSDraggingSession *)session endedAtPoint:(NSPoint)screenPoint operation:(NSDragOperation)operation
|
||||
{
|
||||
Q_UNUSED(session);
|
||||
Q_UNUSED(screenPoint);
|
||||
@ -295,6 +294,8 @@ static QPoint mapWindowCoordinates(QWindow *source, QWindow *target, QPoint poin
|
||||
nativeDrag->setAcceptedAction(qt_mac_mapNSDragOperation(operation));
|
||||
|
||||
m_buttons = currentlyPressedMouseButtons();
|
||||
|
||||
qCDebug(lcQpaMouse) << "Drag session" << session << "ended, with" << m_buttons;
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -93,6 +93,7 @@
|
||||
|
||||
- (void)resetMouseButtons
|
||||
{
|
||||
qCDebug(lcQpaMouse) << "Reseting mouse buttons";
|
||||
m_buttons = Qt::NoButton;
|
||||
m_frameStrutButtons = Qt::NoButton;
|
||||
}
|
||||
@ -145,6 +146,9 @@
|
||||
QPoint qtScreenPoint = QCocoaScreen::mapFromNative(screenPoint).toPoint();
|
||||
|
||||
ulong timestamp = [theEvent timestamp] * 1000;
|
||||
|
||||
auto eventType = cocoaEvent2QtMouseEvent(theEvent);
|
||||
qCInfo(lcQpaMouse) << "Frame-strut" << eventType << "at" << qtWindowPoint << "with" << m_frameStrutButtons << "in" << self.window;
|
||||
QWindowSystemInterface::handleFrameStrutMouseEvent(m_platformWindow->window(), timestamp, qtWindowPoint, qtScreenPoint, m_frameStrutButtons);
|
||||
}
|
||||
@end
|
||||
@ -153,6 +157,19 @@
|
||||
|
||||
- (void)initMouse
|
||||
{
|
||||
m_buttons = Qt::NoButton;
|
||||
m_acceptedMouseDowns = Qt::NoButton;
|
||||
m_frameStrutButtons = Qt::NoButton;
|
||||
|
||||
m_scrolling = false;
|
||||
self.cursor = nil;
|
||||
|
||||
m_sendUpAsRightButton = false;
|
||||
m_dontOverrideCtrlLMB = qt_mac_resolveOption(false, m_platformWindow->window(),
|
||||
"_q_platform_MacDontOverrideCtrlLMB", "QT_MAC_DONT_OVERRIDE_CTRL_LMB");
|
||||
|
||||
m_mouseMoveHelper = [[QT_MANGLE_NAMESPACE(QNSViewMouseMoveHelper) alloc] initWithView:self];
|
||||
|
||||
NSUInteger trackingOptions = NSTrackingActiveInActiveApp
|
||||
| NSTrackingMouseEnteredAndExited | NSTrackingCursorUpdate;
|
||||
|
||||
@ -241,6 +258,11 @@
|
||||
button = Qt::RightButton;
|
||||
const auto eventType = cocoaEvent2QtMouseEvent(theEvent);
|
||||
|
||||
if (eventType == QEvent::MouseMove)
|
||||
qCDebug(lcQpaMouse) << eventType << "at" << qtWindowPoint << "with" << buttons;
|
||||
else
|
||||
qCInfo(lcQpaMouse) << eventType << "of" << button << "at" << qtWindowPoint << "with" << buttons;
|
||||
|
||||
QWindowSystemInterface::handleMouseEvent(targetView->m_platformWindow->window(),
|
||||
timestamp, qtWindowPoint, qtScreenPoint,
|
||||
buttons, button, eventType, modifiers);
|
||||
@ -446,16 +468,16 @@
|
||||
|
||||
- (void)cursorUpdate:(NSEvent *)theEvent
|
||||
{
|
||||
qCDebug(lcQpaMouse) << "Updating cursor for" << self << "to" << self.cursor;
|
||||
|
||||
// Note: We do not get this callback when moving from a subview that
|
||||
// uses the legacy cursorRect API, so the cursor is reset to the arrow
|
||||
// cursor. See rdar://34183708
|
||||
|
||||
if (self.cursor)
|
||||
if (self.cursor && self.cursor != NSCursor.currentCursor) {
|
||||
qCInfo(lcQpaMouse) << "Updating cursor for" << self << "to" << self.cursor;
|
||||
[self.cursor set];
|
||||
else
|
||||
} else {
|
||||
[super cursorUpdate:theEvent];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)mouseMovedImpl:(NSEvent *)theEvent
|
||||
@ -510,6 +532,8 @@
|
||||
QPointF screenPoint;
|
||||
[self convertFromScreen:[self screenMousePoint:theEvent] toWindowPoint:&windowPoint andScreenPoint:&screenPoint];
|
||||
m_platformWindow->m_enterLeaveTargetWindow = m_platformWindow->childWindowAt(windowPoint.toPoint());
|
||||
|
||||
qCInfo(lcQpaMouse) << QEvent::Enter << self << "at" << windowPoint << "with" << currentlyPressedMouseButtons();
|
||||
QWindowSystemInterface::handleEnterEvent(m_platformWindow->m_enterLeaveTargetWindow, windowPoint, screenPoint);
|
||||
}
|
||||
|
||||
@ -528,6 +552,7 @@
|
||||
if (!m_platformWindow->isContentView())
|
||||
return;
|
||||
|
||||
qCInfo(lcQpaMouse) << QEvent::Leave << self;
|
||||
QWindowSystemInterface::handleLeaveEvent(m_platformWindow->m_enterLeaveTargetWindow);
|
||||
m_platformWindow->m_enterLeaveTargetWindow = 0;
|
||||
}
|
||||
@ -626,8 +651,10 @@
|
||||
// "isInverted": natural OS X scrolling, inverted from the Qt/other platform/Jens perspective.
|
||||
bool isInverted = [theEvent isDirectionInvertedFromDevice];
|
||||
|
||||
qCDebug(lcQpaMouse) << "scroll wheel @ window pos" << qt_windowPoint << "delta px" << pixelDelta
|
||||
<< "angle" << angleDelta << "phase" << phase << (isInverted ? "inverted" : "");
|
||||
qCInfo(lcQpaMouse).nospace() << phase << " at " << qt_windowPoint
|
||||
<< " pixelDelta=" << pixelDelta << " angleDelta=" << angleDelta
|
||||
<< (isInverted ? " inverted=true" : "");
|
||||
|
||||
QWindowSystemInterface::handleWheelEvent(m_platformWindow->window(), qt_timestamp, qt_windowPoint,
|
||||
qt_screenPoint, pixelDelta, angleDelta, m_currentWheelModifiers, phase, source, isInverted);
|
||||
}
|
||||
|
@ -50,6 +50,7 @@
|
||||
// External mode.usage:
|
||||
//
|
||||
// var config = {
|
||||
// canvasElements : [$("canvas-id")],
|
||||
// showLoader: function() {
|
||||
// loader.style.display = 'block'
|
||||
// canvas.style.display = 'hidden'
|
||||
@ -69,6 +70,8 @@
|
||||
// One or more HTML elements. QtLoader will display loader elements
|
||||
// on these while loading the applicaton, and replace the loader with a
|
||||
// canvas on load complete.
|
||||
// canvasElements : [canvas-element, ...]
|
||||
// One or more canvas elements.
|
||||
// showLoader : function(status, containerElement)
|
||||
// Optional loading element constructor function. Implement to create
|
||||
// a custom loading screen. This function may be called multiple times,
|
||||
@ -146,8 +149,25 @@ function QtLoader(config)
|
||||
while (element.firstChild) element.removeChild(element.firstChild);
|
||||
}
|
||||
|
||||
// Set default state handler functions if needed
|
||||
function createCanvas() {
|
||||
var canvas = document.createElement("canvas");
|
||||
canvas.className = "QtCanvas";
|
||||
canvas.style.height = "100%";
|
||||
canvas.style.width = "100%";
|
||||
|
||||
// Set contentEditable in order to enable clipboard events; hide the resulting focus frame.
|
||||
canvas.contentEditable = true;
|
||||
canvas.style.outline = "0px solid transparent";
|
||||
canvas.style.cursor = "default";
|
||||
|
||||
return canvas;
|
||||
}
|
||||
|
||||
// Set default state handler functions and create canvases if needed
|
||||
if (config.containerElements !== undefined) {
|
||||
|
||||
config.canvasElements = config.containerElements.map(createCanvas);
|
||||
|
||||
config.showError = config.showError || function(errorText, container) {
|
||||
removeChildren(container);
|
||||
var errorTextElement = document.createElement("text");
|
||||
@ -164,12 +184,8 @@ function QtLoader(config)
|
||||
return loadingText;
|
||||
};
|
||||
|
||||
config.showCanvas = config.showCanvas || function(container) {
|
||||
config.showCanvas = config.showCanvas || function(canvas, container) {
|
||||
removeChildren(container);
|
||||
var canvas = document.createElement("canvas");
|
||||
canvas.className = "QtCanvas"
|
||||
canvas.style = "height: 100%; width: 100%;"
|
||||
return canvas;
|
||||
}
|
||||
|
||||
config.showExit = config.showExit || function(crashed, exitCode, container) {
|
||||
@ -384,6 +400,8 @@ function QtLoader(config)
|
||||
|
||||
Module.mainScriptUrlOrBlob = new Blob([emscriptenModuleSource], {type: 'text/javascript'});
|
||||
|
||||
Module.qtCanvasElements = config.canvasElements;
|
||||
|
||||
config.restart = function() {
|
||||
|
||||
// Restart by reloading the page. This will wipe all state which means
|
||||
@ -438,19 +456,17 @@ function QtLoader(config)
|
||||
}
|
||||
|
||||
function setCanvasContent() {
|
||||
var firstCanvas;
|
||||
if (config.containerElements === undefined) {
|
||||
firstCanvas = config.showCanvas();
|
||||
} else {
|
||||
for (container of config.containerElements) {
|
||||
var canvasElement = config.showCanvas(container);
|
||||
container.appendChild(canvasElement);
|
||||
}
|
||||
firstCanvas = config.containerElements[0].firstChild;
|
||||
if (config.showCanvas !== undefined)
|
||||
config.showCanvas();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Module.canvas === undefined) {
|
||||
Module.canvas = firstCanvas;
|
||||
for (var i = 0; i < config.containerElements.length; ++i) {
|
||||
var container = config.containerElements[i];
|
||||
var canvas = config.canvasElements[i];
|
||||
config.showCanvas(canvas, container);
|
||||
container.appendChild(canvas);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -67,23 +67,42 @@ static void qClipboardPromiseResolve(emscripten::val something)
|
||||
pasteClipboardData(emscripten::val("text/plain"), something);
|
||||
}
|
||||
|
||||
static void qClipboardCopyTo(val event)
|
||||
static void qClipboardCutTo(val event)
|
||||
{
|
||||
val target = event["target"];
|
||||
val clipboard = event["clipboardData"];
|
||||
if (!QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi) {
|
||||
// Send synthetic Ctrl+X to make the app cut data to Qt's clipboard
|
||||
QWindowSystemInterface::handleKeyEvent<QWindowSystemInterface::SynchronousDelivery>(
|
||||
0, QEvent::KeyPress, Qt::Key_X, Qt::ControlModifier, "X");
|
||||
}
|
||||
|
||||
val module = val::global("Module");
|
||||
val clipdata = module.call<val>("getClipboardData");
|
||||
val clipFormat = module.call<val>("getClipboardFormat");
|
||||
clipboard.call<void>("setData", clipFormat, clipdata);
|
||||
target.call<void>("preventDefault");
|
||||
event["clipboardData"].call<void>("setData", clipFormat, clipdata);
|
||||
event.call<void>("preventDefault");
|
||||
}
|
||||
|
||||
static void qClipboardCopyTo(val event)
|
||||
{
|
||||
if (!QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi) {
|
||||
// Send synthetic Ctrl+C to make the app copy data to Qt's clipboard
|
||||
QWindowSystemInterface::handleKeyEvent<QWindowSystemInterface::SynchronousDelivery>(
|
||||
0, QEvent::KeyPress, Qt::Key_C, Qt::ControlModifier, "C");
|
||||
}
|
||||
|
||||
val module = val::global("Module");
|
||||
val clipdata = module.call<val>("getClipboardData");
|
||||
val clipFormat = module.call<val>("getClipboardFormat");
|
||||
event["clipboardData"].call<void>("setData", clipFormat, clipdata);
|
||||
event.call<void>("preventDefault");
|
||||
}
|
||||
|
||||
static void qClipboardPasteTo(val event)
|
||||
{
|
||||
val target = event["clipboardData"];
|
||||
val module = val::global("Module");
|
||||
val clipdata = module.call<val>("getClipboardData");
|
||||
bool hasClipboardApi = QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi;
|
||||
val clipdata = hasClipboardApi ?
|
||||
val::global("Module").call<val>("getClipboardData") :
|
||||
event["clipboardData"].call<val>("getData", std::string("text"));
|
||||
|
||||
const std::string data = clipdata.as<std::string>();
|
||||
if (data.length() > 0) {
|
||||
@ -99,13 +118,16 @@ EMSCRIPTEN_BINDINGS(clipboard_module) {
|
||||
function("getClipboardFormat", &getClipboardFormat);
|
||||
function("pasteClipboardData", &pasteClipboardData);
|
||||
function("qClipboardPromiseResolve", &qClipboardPromiseResolve);
|
||||
function("qClipboardCutTo", &qClipboardCutTo);
|
||||
function("qClipboardCopyTo", &qClipboardCopyTo);
|
||||
function("qClipboardPasteTo", &qClipboardPasteTo);
|
||||
}
|
||||
|
||||
QWasmClipboard::QWasmClipboard() :
|
||||
hasClipboardApi(false)
|
||||
QWasmClipboard::QWasmClipboard()
|
||||
{
|
||||
val clipboard = val::global("navigator")["clipboard"];
|
||||
hasClipboardApi = (!clipboard.isUndefined() && !clipboard["readText"].isUndefined());
|
||||
|
||||
initClipboardEvents();
|
||||
}
|
||||
|
||||
@ -157,29 +179,32 @@ void QWasmClipboard::qWasmClipboardPaste(QMimeData *mData)
|
||||
|
||||
void QWasmClipboard::initClipboardEvents()
|
||||
{
|
||||
val navigator = val::global("navigator");
|
||||
val permissions = navigator["permissions"];
|
||||
val clipboard = navigator["clipboard"];
|
||||
if (!hasClipboardApi)
|
||||
return;
|
||||
|
||||
hasClipboardApi = (!clipboard.isUndefined());
|
||||
if (hasClipboardApi) {
|
||||
val readPermissionsMap = val::object();
|
||||
readPermissionsMap.set("name", val("clipboard-read"));
|
||||
permissions.call<val>("query", readPermissionsMap);
|
||||
val permissions = val::global("navigator")["permissions"];
|
||||
val readPermissionsMap = val::object();
|
||||
readPermissionsMap.set("name", val("clipboard-read"));
|
||||
permissions.call<val>("query", readPermissionsMap);
|
||||
|
||||
val writePermissionsMap = val::object();
|
||||
writePermissionsMap.set("name", val("clipboard-write"));
|
||||
permissions.call<val>("query", writePermissionsMap);
|
||||
val writePermissionsMap = val::object();
|
||||
writePermissionsMap.set("name", val("clipboard-write"));
|
||||
permissions.call<val>("query", writePermissionsMap);
|
||||
}
|
||||
|
||||
} else {
|
||||
void QWasmClipboard::installEventHandlers(const QString &canvasId)
|
||||
{
|
||||
if (hasClipboardApi)
|
||||
return;
|
||||
|
||||
val window = val::global("window");
|
||||
window.call<void>("addEventListener", std::string("paste"),
|
||||
val::module_property("qClipboardPasteTo"));
|
||||
|
||||
window.call<void>("addEventListener", std::string("copy"),
|
||||
val::module_property("qClipboardCopyTo"));
|
||||
}
|
||||
// Fallback path for browsers which do not support direct clipboard access
|
||||
val canvas = val::global(canvasId.toUtf8().constData());
|
||||
canvas.call<void>("addEventListener", std::string("cut"),
|
||||
val::module_property("qClipboardCutTo"));
|
||||
canvas.call<void>("addEventListener", std::string("copy"),
|
||||
val::module_property("qClipboardCopyTo"));
|
||||
canvas.call<void>("addEventListener", std::string("paste"),
|
||||
val::module_property("qClipboardPasteTo"));
|
||||
}
|
||||
|
||||
void QWasmClipboard::readTextFromClipboard()
|
||||
|
@ -51,6 +51,7 @@ public:
|
||||
|
||||
static void qWasmClipboardPaste(QMimeData *mData);
|
||||
void initClipboardEvents();
|
||||
void installEventHandlers(const QString &canvasId);
|
||||
bool hasClipboardApi;
|
||||
void readTextFromClipboard();
|
||||
void writeTextToClipboard();
|
||||
|
@ -56,8 +56,9 @@ QWasmCompositedWindow::QWasmCompositedWindow()
|
||||
{
|
||||
}
|
||||
|
||||
QWasmCompositor::QWasmCompositor()
|
||||
: m_frameBuffer(nullptr)
|
||||
QWasmCompositor::QWasmCompositor(QWasmScreen *screen)
|
||||
:QObject(screen)
|
||||
, m_frameBuffer(nullptr)
|
||||
, m_blitter(new QOpenGLTextureBlitter)
|
||||
, m_needComposit(false)
|
||||
, m_inFlush(false)
|
||||
@ -107,11 +108,6 @@ void QWasmCompositor::removeWindow(QWasmWindow *window)
|
||||
notifyTopWindowChanged(window);
|
||||
}
|
||||
|
||||
void QWasmCompositor::setScreen(QWasmScreen *screen)
|
||||
{
|
||||
m_screen = screen;
|
||||
}
|
||||
|
||||
void QWasmCompositor::setVisible(QWasmWindow *window, bool visible)
|
||||
{
|
||||
QWasmCompositedWindow &compositedWindow = m_compositedWindows[window];
|
||||
@ -654,7 +650,7 @@ void QWasmCompositor::frame()
|
||||
|
||||
m_needComposit = false;
|
||||
|
||||
if (m_windowStack.empty() || !m_screen)
|
||||
if (m_windowStack.empty() || !screen())
|
||||
return;
|
||||
|
||||
QWasmWindow *someWindow = nullptr;
|
||||
@ -673,7 +669,7 @@ void QWasmCompositor::frame()
|
||||
if (m_context.isNull()) {
|
||||
m_context.reset(new QOpenGLContext());
|
||||
//mContext->setFormat(mScreen->format());
|
||||
m_context->setScreen(m_screen->screen());
|
||||
m_context->setScreen(screen()->screen());
|
||||
m_context->create();
|
||||
}
|
||||
|
||||
@ -682,8 +678,8 @@ void QWasmCompositor::frame()
|
||||
if (!m_blitter->isCreated())
|
||||
m_blitter->create();
|
||||
|
||||
qreal dpr = m_screen->devicePixelRatio();
|
||||
glViewport(0, 0, m_screen->geometry().width() * dpr, m_screen->geometry().height() * dpr);
|
||||
qreal dpr = screen()->devicePixelRatio();
|
||||
glViewport(0, 0, screen()->geometry().width() * dpr, screen()->geometry().height() * dpr);
|
||||
|
||||
m_context->functions()->glClearColor(0.2, 0.2, 0.2, 1.0);
|
||||
m_context->functions()->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
@ -697,7 +693,7 @@ void QWasmCompositor::frame()
|
||||
if (!compositedWindow.visible)
|
||||
continue;
|
||||
|
||||
drawWindow(m_blitter.data(), m_screen, window);
|
||||
drawWindow(m_blitter.data(), screen(), window);
|
||||
}
|
||||
|
||||
m_blitter->release();
|
||||
@ -719,3 +715,8 @@ void QWasmCompositor::notifyTopWindowChanged(QWasmWindow *window)
|
||||
requestRedraw();
|
||||
QWindowSystemInterface::handleWindowActivated(window->window());
|
||||
}
|
||||
|
||||
QWasmScreen *QWasmCompositor::screen()
|
||||
{
|
||||
return static_cast<QWasmScreen *>(parent());
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ class QWasmCompositor : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QWasmCompositor();
|
||||
QWasmCompositor(QWasmScreen *screen);
|
||||
~QWasmCompositor();
|
||||
|
||||
enum QWasmSubControl {
|
||||
@ -103,7 +103,6 @@ public:
|
||||
|
||||
void addWindow(QWasmWindow *window, QWasmWindow *parentWindow = nullptr);
|
||||
void removeWindow(QWasmWindow *window);
|
||||
void setScreen(QWasmScreen *screen);
|
||||
|
||||
void setVisible(QWasmWindow *window, bool visible);
|
||||
void raise(QWasmWindow *window);
|
||||
@ -129,8 +128,7 @@ private slots:
|
||||
void frame();
|
||||
|
||||
private:
|
||||
void createFrameBuffer();
|
||||
void flushCompletedCallback(int32_t);
|
||||
QWasmScreen *screen();
|
||||
void notifyTopWindowChanged(QWasmWindow *window);
|
||||
void drawWindow(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window);
|
||||
void drawWindowContent(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window);
|
||||
@ -142,7 +140,6 @@ private:
|
||||
QImage *m_frameBuffer;
|
||||
QScopedPointer<QOpenGLContext> m_context;
|
||||
QScopedPointer<QOpenGLTextureBlitter> m_blitter;
|
||||
QWasmScreen *m_screen;
|
||||
|
||||
QHash<QWasmWindow *, QWasmCompositedWindow> m_compositedWindows;
|
||||
QList<QWasmWindow *> m_windowStack;
|
||||
|
@ -28,20 +28,21 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include "qwasmcursor.h"
|
||||
#include "qwasmscreen.h"
|
||||
|
||||
#include <QtCore/qdebug.h>
|
||||
#include <QtGui/qwindow.h>
|
||||
|
||||
#include <emscripten/emscripten.h>
|
||||
#include <emscripten/bind.h>
|
||||
|
||||
void QWasmCursor::changeCursor(QCursor *windowCursor, QWindow *window)
|
||||
{
|
||||
if (windowCursor == nullptr)
|
||||
if (!windowCursor || !window)
|
||||
return;
|
||||
QScreen *screen = window->screen();
|
||||
if (!screen)
|
||||
return;
|
||||
|
||||
// FIXME: The HTML5 plugin sets the cursor on the native canvas; when using multiple windows
|
||||
// multiple cursors need to be managed taking mouse postion and stacking into account.
|
||||
Q_UNUSED(window);
|
||||
|
||||
// Bitmap and custom cursors are not implemented (will fall back to "auto")
|
||||
if (windowCursor->shape() == Qt::BitmapCursor || windowCursor->shape() >= Qt::CustomCursor)
|
||||
@ -52,8 +53,9 @@ void QWasmCursor::changeCursor(QCursor *windowCursor, QWindow *window)
|
||||
if (htmlCursorName.isEmpty())
|
||||
htmlCursorName = "auto";
|
||||
|
||||
// Set cursor on the main canvas
|
||||
emscripten::val canvasStyle = emscripten::val::module_property("canvas")["style"];
|
||||
// Set cursor on the canvas
|
||||
QString canvasId = QWasmScreen::get(screen)->canvasId();
|
||||
emscripten::val canvasStyle = emscripten::val::global(canvasId.toUtf8().constData())["style"];
|
||||
canvasStyle.set("cursor", emscripten::val(htmlCursorName.constData()));
|
||||
}
|
||||
|
||||
|
@ -320,41 +320,35 @@ EMSCRIPTEN_BINDINGS(mouse_module) {
|
||||
function("mouseWheelEvent", &mouseWheelEvent);
|
||||
}
|
||||
|
||||
QWasmEventTranslator::QWasmEventTranslator(QObject *parent)
|
||||
: QObject(parent)
|
||||
QWasmEventTranslator::QWasmEventTranslator(QWasmScreen *screen)
|
||||
: QObject(screen)
|
||||
, draggedWindow(nullptr)
|
||||
, lastWindow(nullptr)
|
||||
, pressedButtons(Qt::NoButton)
|
||||
, resizeMode(QWasmWindow::ResizeNone)
|
||||
{
|
||||
emscripten_set_keydown_callback(0, (void *)this, 1, &keyboard_cb);
|
||||
emscripten_set_keyup_callback(0, (void *)this, 1, &keyboard_cb);
|
||||
|
||||
emscripten_set_mousedown_callback(0, (void *)this, 1, &mouse_cb);
|
||||
emscripten_set_mouseup_callback(0, (void *)this, 1, &mouse_cb);
|
||||
emscripten_set_mousemove_callback(0, (void *)this, 1, &mouse_cb);
|
||||
|
||||
emscripten_set_focus_callback(0, (void *)this, 1, &focus_cb);
|
||||
|
||||
emscripten_set_wheel_callback(0, (void *)this, 1, &wheel_cb);
|
||||
|
||||
touchDevice = new QTouchDevice;
|
||||
touchDevice->setType(QTouchDevice::TouchScreen);
|
||||
touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::NormalizedPosition);
|
||||
QWindowSystemInterface::registerTouchDevice(touchDevice);
|
||||
|
||||
emscripten_set_touchstart_callback("#canvas", (void *)this, 1, &touchCallback);
|
||||
emscripten_set_touchend_callback("#canvas", (void *)this, 1, &touchCallback);
|
||||
emscripten_set_touchmove_callback("#canvas", (void *)this, 1, &touchCallback);
|
||||
emscripten_set_touchcancel_callback("#canvas", (void *)this, 1, &touchCallback);
|
||||
initEventHandlers();
|
||||
}
|
||||
|
||||
void QWasmEventTranslator::initEventHandlers()
|
||||
{
|
||||
qDebug() << "QWasmEventTranslator::initEventHandlers";
|
||||
|
||||
QByteArray _canvasId = screen()->canvasId().toUtf8();
|
||||
const char *canvasId = _canvasId.constData();
|
||||
|
||||
// The Platform Detect: expand coverage and move as needed
|
||||
enum Platform {
|
||||
GenericPlatform,
|
||||
MacOSPlatform
|
||||
};
|
||||
Platform platform = Platform(emscripten::val::global("navigator")["platform"]
|
||||
.call<bool>("includes", emscripten::val("Mac")));
|
||||
Platform platform = Platform(emscripten::val::global("navigator")["platform"]
|
||||
.call<bool>("includes", emscripten::val("Mac")));
|
||||
g_usePlatformMacCtrlMetaSwitching = (platform == MacOSPlatform);
|
||||
|
||||
if (platform == MacOSPlatform) {
|
||||
@ -362,11 +356,30 @@ QWasmEventTranslator::QWasmEventTranslator(QObject *parent)
|
||||
|
||||
if (emscripten::val::global("window")["safari"].isUndefined()) {
|
||||
|
||||
emscripten::val::global("canvas").call<void>("addEventListener",
|
||||
emscripten::val::global(canvasId).call<void>("addEventListener",
|
||||
std::string("wheel"),
|
||||
val::module_property("mouseWheelEvent"));
|
||||
}
|
||||
}
|
||||
|
||||
emscripten_set_keydown_callback(canvasId, (void *)this, 1, &keyboard_cb);
|
||||
emscripten_set_keyup_callback(canvasId, (void *)this, 1, &keyboard_cb);
|
||||
|
||||
emscripten_set_mousedown_callback(canvasId, (void *)this, 1, &mouse_cb);
|
||||
emscripten_set_mouseup_callback(canvasId, (void *)this, 1, &mouse_cb);
|
||||
emscripten_set_mousemove_callback(canvasId, (void *)this, 1, &mouse_cb);
|
||||
|
||||
emscripten_set_focus_callback(canvasId, (void *)this, 1, &focus_cb);
|
||||
|
||||
emscripten_set_wheel_callback(canvasId, (void *)this, 1, &wheel_cb);
|
||||
|
||||
emscripten_set_touchstart_callback(canvasId, (void *)this, 1, &touchCallback);
|
||||
emscripten_set_touchend_callback(canvasId, (void *)this, 1, &touchCallback);
|
||||
emscripten_set_touchmove_callback(canvasId, (void *)this, 1, &touchCallback);
|
||||
emscripten_set_touchcancel_callback(canvasId, (void *)this, 1, &touchCallback);
|
||||
|
||||
emscripten_set_resize_callback(nullptr, (void *)this, 1, uiEvent_cb); // Note: handles browser window resize
|
||||
|
||||
}
|
||||
|
||||
template <typename Event>
|
||||
@ -415,6 +428,11 @@ int QWasmEventTranslator::keyboard_cb(int eventType, const EmscriptenKeyboardEve
|
||||
return accepted ? 1 : 0;
|
||||
}
|
||||
|
||||
QWasmScreen *QWasmEventTranslator::screen()
|
||||
{
|
||||
return static_cast<QWasmScreen *>(parent());
|
||||
}
|
||||
|
||||
Qt::Key QWasmEventTranslator::translateEmscriptKey(const EmscriptenKeyboardEvent *emscriptKey)
|
||||
{
|
||||
Qt::Key qtKey = Qt::Key_unknown;
|
||||
@ -531,14 +549,14 @@ void resizeWindow(QWindow *window, QWasmWindow::ResizeMode mode,
|
||||
void QWasmEventTranslator::processMouse(int eventType, const EmscriptenMouseEvent *mouseEvent)
|
||||
{
|
||||
auto timestamp = mouseEvent->timestamp;
|
||||
QPoint point(mouseEvent->canvasX, mouseEvent->canvasY);
|
||||
QPoint point(mouseEvent->targetX, mouseEvent->targetY);
|
||||
|
||||
QEvent::Type buttonEventType = QEvent::None;
|
||||
|
||||
Qt::MouseButton button = translateMouseButton(mouseEvent->button);
|
||||
Qt::KeyboardModifiers modifiers = translateMouseEventModifier(mouseEvent);
|
||||
|
||||
QWindow *window2 = QWasmIntegration::get()->compositor()->windowAt(point, 5);
|
||||
QWindow *window2 = screen()->compositor()->windowAt(point, 5);
|
||||
if (window2 != nullptr)
|
||||
lastWindow = window2;
|
||||
|
||||
@ -635,6 +653,7 @@ int QWasmEventTranslator::wheel_cb(int eventType, const EmscriptenWheelEvent *wh
|
||||
{
|
||||
Q_UNUSED(eventType)
|
||||
|
||||
QWasmEventTranslator *eventTranslator = static_cast<QWasmEventTranslator *>(userData);
|
||||
EmscriptenMouseEvent mouseEvent = wheelEvent->mouse;
|
||||
|
||||
int scrollFactor = 0;
|
||||
@ -658,7 +677,7 @@ int QWasmEventTranslator::wheel_cb(int eventType, const EmscriptenWheelEvent *wh
|
||||
auto timestamp = mouseEvent.timestamp;
|
||||
QPoint globalPoint(mouseEvent.canvasX, mouseEvent.canvasY);
|
||||
|
||||
QWindow *window2 = QWasmIntegration::get()->compositor()->windowAt(globalPoint, 5);
|
||||
QWindow *window2 = eventTranslator->screen()->compositor()->windowAt(globalPoint, 5);
|
||||
|
||||
QPoint localPoint(globalPoint.x() - window2->geometry().x(), globalPoint.y() - window2->geometry().y());
|
||||
|
||||
@ -676,6 +695,7 @@ int QWasmEventTranslator::wheel_cb(int eventType, const EmscriptenWheelEvent *wh
|
||||
|
||||
int QWasmEventTranslator::touchCallback(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)
|
||||
{
|
||||
QWasmEventTranslator *eventTranslator = static_cast<QWasmEventTranslator *>(userData);
|
||||
QList<QWindowSystemInterface::TouchPoint> touchPointList;
|
||||
touchPointList.reserve(touchEvent->numTouches);
|
||||
QWindow *window2;
|
||||
@ -685,7 +705,7 @@ int QWasmEventTranslator::touchCallback(int eventType, const EmscriptenTouchEven
|
||||
const EmscriptenTouchPoint *touches = &touchEvent->touches[i];
|
||||
|
||||
QPoint point(touches->canvasX, touches->canvasY);
|
||||
window2 = QWasmIntegration::get()->compositor()->windowAt(point, 5);
|
||||
window2 = eventTranslator->screen()->compositor()->windowAt(point, 5);
|
||||
|
||||
QWindowSystemInterface::TouchPoint touchPoint;
|
||||
|
||||
@ -832,6 +852,14 @@ bool QWasmEventTranslator::processKeyboard(int eventType, const EmscriptenKeyboa
|
||||
return 0;
|
||||
|
||||
QFlags<Qt::KeyboardModifier> mods = translateKeyboardEventModifier(keyEvent);
|
||||
|
||||
// Clipboard fallback path: cut/copy/paste are handled by clipboard event
|
||||
// handlers if direct clipboard access is not available.
|
||||
if (!QWasmIntegration::get()->getWasmClipboard()->hasClipboardApi && modifiers & Qt::ControlModifier &&
|
||||
(qtKey == Qt::Key_X || qtKey == Qt::Key_C || qtKey == Qt::Key_V)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool accepted = false;
|
||||
|
||||
if (keyType == QEvent::KeyPress &&
|
||||
@ -857,4 +885,19 @@ bool QWasmEventTranslator::processKeyboard(int eventType, const EmscriptenKeyboa
|
||||
return accepted;
|
||||
}
|
||||
|
||||
int QWasmEventTranslator::uiEvent_cb(int eventType, const EmscriptenUiEvent *e, void *userData)
|
||||
{
|
||||
Q_UNUSED(e)
|
||||
QWasmEventTranslator *eventTranslator = static_cast<QWasmEventTranslator *>(userData);
|
||||
|
||||
if (eventType == EMSCRIPTEN_EVENT_RESIZE) {
|
||||
// This resize event is called when the HTML window is resized. Depending
|
||||
// on the page layout the the canvas might also have been resized, so we
|
||||
// update the Qt screen size (and canvas render size).
|
||||
eventTranslator->screen()->updateQScreenAndCanvasRenderSize();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -48,7 +48,7 @@ class QWasmEventTranslator : public QObject
|
||||
|
||||
public:
|
||||
|
||||
explicit QWasmEventTranslator(QObject *parent = 0);
|
||||
explicit QWasmEventTranslator(QWasmScreen *screen);
|
||||
|
||||
static int keyboard_cb(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData);
|
||||
static int mouse_cb(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData);
|
||||
@ -57,12 +57,15 @@ public:
|
||||
|
||||
static int touchCallback(int eventType, const EmscriptenTouchEvent *ev, void *userData);
|
||||
|
||||
static int uiEvent_cb(int eventType, const EmscriptenUiEvent *e, void *userData);
|
||||
|
||||
void processEvents();
|
||||
void initEventHandlers();
|
||||
|
||||
Q_SIGNALS:
|
||||
void getWindowAt(const QPoint &point, QWindow **window);
|
||||
private:
|
||||
|
||||
QWasmScreen *screen();
|
||||
Qt::Key translateEmscriptKey(const EmscriptenKeyboardEvent *emscriptKey);
|
||||
template <typename Event>
|
||||
QFlags<Qt::KeyboardModifier> translatKeyModifier(const Event *event);
|
||||
|
@ -70,29 +70,35 @@ QWasmIntegration *QWasmIntegration::s_instance;
|
||||
|
||||
QWasmIntegration::QWasmIntegration()
|
||||
: m_fontDb(nullptr),
|
||||
m_compositor(new QWasmCompositor),
|
||||
m_screen(new QWasmScreen(m_compositor)),
|
||||
m_eventDispatcher(nullptr),
|
||||
m_clipboard(new QWasmClipboard)
|
||||
{
|
||||
s_instance = this;
|
||||
|
||||
updateQScreenAndCanvasRenderSize();
|
||||
screenAdded(m_screen);
|
||||
emscripten_set_resize_callback(0, (void *)this, 1, uiEvent_cb);
|
||||
// We expect that qtloader.js has populated Module.qtCanvasElements with one or more canvases.
|
||||
// Also check Module.canvas, which may be set if the emscripen or a custom loader is used.
|
||||
emscripten::val qtCanvaseElements = val::module_property("qtCanvasElements");
|
||||
emscripten::val canvas = val::module_property("canvas");
|
||||
|
||||
m_eventTranslator = new QWasmEventTranslator;
|
||||
if (!qtCanvaseElements.isUndefined()) {
|
||||
int screenCount = qtCanvaseElements["length"].as<int>();
|
||||
for (int i = 0; i < screenCount; ++i) {
|
||||
emscripten::val canvas = qtCanvaseElements[i].as<emscripten::val>();
|
||||
QString canvasId = QString::fromStdString(canvas["id"].as<std::string>());
|
||||
addScreen(canvasId);
|
||||
}
|
||||
} else if (!canvas.isUndefined()){
|
||||
QString canvasId = QString::fromStdString(canvas["id"].as<std::string>());
|
||||
addScreen(canvasId);
|
||||
}
|
||||
|
||||
emscripten::val::global("window").set("onbeforeunload", val::module_property("browserBeforeUnload"));
|
||||
|
||||
}
|
||||
|
||||
QWasmIntegration::~QWasmIntegration()
|
||||
{
|
||||
delete m_compositor;
|
||||
destroyScreen(m_screen);
|
||||
delete m_fontDb;
|
||||
delete m_eventTranslator;
|
||||
qDeleteAll(m_screens);
|
||||
s_instance = nullptr;
|
||||
}
|
||||
|
||||
@ -117,13 +123,15 @@ bool QWasmIntegration::hasCapability(QPlatformIntegration::Capability cap) const
|
||||
|
||||
QPlatformWindow *QWasmIntegration::createPlatformWindow(QWindow *window) const
|
||||
{
|
||||
return new QWasmWindow(window, m_compositor, m_backingStores.value(window));
|
||||
QWasmCompositor *compositor = QWasmScreen::get(window->screen())->compositor();
|
||||
return new QWasmWindow(window, compositor, m_backingStores.value(window));
|
||||
}
|
||||
|
||||
QPlatformBackingStore *QWasmIntegration::createPlatformBackingStore(QWindow *window) const
|
||||
{
|
||||
#ifndef QT_NO_OPENGL
|
||||
QWasmBackingStore *backingStore = new QWasmBackingStore(m_compositor, window);
|
||||
QWasmCompositor *compositor = QWasmScreen::get(window->screen())->compositor();
|
||||
QWasmBackingStore *backingStore = new QWasmBackingStore(compositor, window);
|
||||
m_backingStores.insert(window, backingStore);
|
||||
return backingStore;
|
||||
#else
|
||||
@ -168,55 +176,22 @@ QPlatformTheme *QWasmIntegration::createPlatformTheme(const QString &name) const
|
||||
return QPlatformIntegration::createPlatformTheme(name);
|
||||
}
|
||||
|
||||
int QWasmIntegration::uiEvent_cb(int eventType, const EmscriptenUiEvent *e, void *userData)
|
||||
{
|
||||
Q_UNUSED(e)
|
||||
Q_UNUSED(userData)
|
||||
|
||||
if (eventType == EMSCRIPTEN_EVENT_RESIZE) {
|
||||
// This resize event is called when the HTML window is resized. Depending
|
||||
// on the page layout the the canvas might also have been resized, so we
|
||||
// update the Qt screen size (and canvas render size).
|
||||
updateQScreenAndCanvasRenderSize();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void set_canvas_size(double width, double height)
|
||||
{
|
||||
emscripten::val canvas = emscripten::val::global("canvas");
|
||||
canvas.set("width", width);
|
||||
canvas.set("height", height);
|
||||
}
|
||||
|
||||
void QWasmIntegration::updateQScreenAndCanvasRenderSize()
|
||||
{
|
||||
// The HTML canvas has two sizes: the CSS size and the canvas render size.
|
||||
// The CSS size is determined according to standard CSS rules, while the
|
||||
// render size is set using the "width" and "height" attributes. The render
|
||||
// size must be set manually and is not auto-updated on CSS size change.
|
||||
// Setting the render size to a value larger than the CSS size enables high-dpi
|
||||
// rendering.
|
||||
|
||||
double css_width;
|
||||
double css_height;
|
||||
emscripten_get_element_css_size(0, &css_width, &css_height);
|
||||
QSizeF cssSize(css_width, css_height);
|
||||
|
||||
QWasmScreen *screen = QWasmIntegration::get()->m_screen;
|
||||
QSizeF canvasSize = cssSize * screen->devicePixelRatio();
|
||||
|
||||
set_canvas_size(canvasSize.width(), canvasSize.height());
|
||||
screen->setGeometry(QRect(QPoint(0, 0), cssSize.toSize()));
|
||||
QWasmIntegration::get()->m_compositor->redrawWindowContent();
|
||||
}
|
||||
|
||||
QPlatformClipboard* QWasmIntegration::clipboard() const
|
||||
{
|
||||
if (!m_clipboard)
|
||||
m_clipboard = new QWasmClipboard;
|
||||
return m_clipboard;
|
||||
}
|
||||
|
||||
QVector<QWasmScreen *> QWasmIntegration::screens()
|
||||
{
|
||||
return m_screens;
|
||||
}
|
||||
|
||||
void QWasmIntegration::addScreen(const QString &canvasId)
|
||||
{
|
||||
QWasmScreen *screen = new QWasmScreen(canvasId);
|
||||
m_clipboard->installEventHandlers(canvasId);
|
||||
m_screens.append(screen);
|
||||
screenAdded(screen);
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -71,24 +71,20 @@ public:
|
||||
QPlatformTheme *createPlatformTheme(const QString &name) const override;
|
||||
QPlatformClipboard *clipboard() const override;
|
||||
|
||||
QWasmScreen *screen() { return m_screen; }
|
||||
QWasmCompositor *compositor() { return m_compositor; }
|
||||
QWasmEventTranslator *eventTranslator() { return m_eventTranslator; }
|
||||
QVector<QWasmScreen *>screens();
|
||||
QWasmClipboard *getWasmClipboard() { return m_clipboard; }
|
||||
|
||||
static QWasmIntegration *get() { return s_instance; }
|
||||
static void QWasmBrowserExit();
|
||||
static void updateQScreenAndCanvasRenderSize();
|
||||
|
||||
private:
|
||||
void addScreen(const QString &canvasId);
|
||||
|
||||
mutable QWasmFontDatabase *m_fontDb;
|
||||
QWasmCompositor *m_compositor;
|
||||
mutable QWasmScreen *m_screen;
|
||||
mutable QWasmEventTranslator *m_eventTranslator;
|
||||
mutable QWasmEventDispatcher *m_eventDispatcher;
|
||||
static int uiEvent_cb(int eventType, const EmscriptenUiEvent *e, void *userData);
|
||||
mutable QHash<QWindow *, QWasmBackingStore *> m_backingStores;
|
||||
|
||||
QVector<QWasmScreen *> m_screens;
|
||||
mutable QWasmClipboard *m_clipboard;
|
||||
static QWasmIntegration *s_instance;
|
||||
};
|
||||
|
@ -28,7 +28,7 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include "qwasmopenglcontext.h"
|
||||
|
||||
#include "qwasmintegration.h"
|
||||
#include <EGL/egl.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
@ -57,7 +57,7 @@ void QWasmOpenGLContext::maybeRecreateEmscriptenContext(QPlatformSurface *surfac
|
||||
emscripten_webgl_destroy_context(m_context);
|
||||
|
||||
// Create new context
|
||||
const char *canvasId = 0; // (use default canvas) FIXME: get the actual canvas from the surface.
|
||||
const QString canvasId = QWasmScreen::get(surface->screen())->canvasId();
|
||||
m_context = createEmscriptenContext(canvasId, m_requestedFormat);
|
||||
|
||||
// Register context-lost callback.
|
||||
@ -73,11 +73,11 @@ void QWasmOpenGLContext::maybeRecreateEmscriptenContext(QPlatformSurface *surfac
|
||||
return true;
|
||||
};
|
||||
bool capture = true;
|
||||
emscripten_set_webglcontextlost_callback(canvasId, this, capture, callback);
|
||||
emscripten_set_webglcontextlost_callback(canvasId.toLocal8Bit().constData(), this, capture, callback);
|
||||
}
|
||||
}
|
||||
|
||||
EMSCRIPTEN_WEBGL_CONTEXT_HANDLE QWasmOpenGLContext::createEmscriptenContext(const char *canvasId, QSurfaceFormat format)
|
||||
EMSCRIPTEN_WEBGL_CONTEXT_HANDLE QWasmOpenGLContext::createEmscriptenContext(const QString &canvasId, QSurfaceFormat format)
|
||||
{
|
||||
EmscriptenWebGLContextAttributes attributes;
|
||||
emscripten_webgl_init_context_attributes(&attributes); // Populate with default attributes
|
||||
@ -96,7 +96,7 @@ EMSCRIPTEN_WEBGL_CONTEXT_HANDLE QWasmOpenGLContext::createEmscriptenContext(cons
|
||||
attributes.depth = format.depthBufferSize() > 0;
|
||||
attributes.stencil = format.stencilBufferSize() > 0;
|
||||
|
||||
EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context = emscripten_webgl_create_context(canvasId, &attributes);
|
||||
EMSCRIPTEN_WEBGL_CONTEXT_HANDLE context = emscripten_webgl_create_context(canvasId.toLocal8Bit().constData(), &attributes);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ public:
|
||||
|
||||
private:
|
||||
void maybeRecreateEmscriptenContext(QPlatformSurface *surface);
|
||||
static EMSCRIPTEN_WEBGL_CONTEXT_HANDLE createEmscriptenContext(const char *canvasId, QSurfaceFormat format);
|
||||
static EMSCRIPTEN_WEBGL_CONTEXT_HANDLE createEmscriptenContext(const QString &canvasId, QSurfaceFormat format);
|
||||
|
||||
bool m_contextLost = false;
|
||||
QSurfaceFormat m_requestedFormat;
|
||||
|
@ -29,8 +29,10 @@
|
||||
|
||||
#include "qwasmscreen.h"
|
||||
#include "qwasmwindow.h"
|
||||
#include "qwasmeventtranslator.h"
|
||||
#include "qwasmcompositor.h"
|
||||
#include <emscripten/bind.h>
|
||||
#include <emscripten/val.h>
|
||||
|
||||
#include <QtEglSupport/private/qeglconvenience_p.h>
|
||||
#ifndef QT_NO_OPENGL
|
||||
@ -44,12 +46,13 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QWasmScreen::QWasmScreen(QWasmCompositor *compositor)
|
||||
: m_compositor(compositor)
|
||||
, m_depth(32)
|
||||
, m_format(QImage::Format_RGB32)
|
||||
QWasmScreen::QWasmScreen(const QString &canvasId)
|
||||
: m_canvasId(canvasId)
|
||||
|
||||
{
|
||||
m_compositor->setScreen(this);
|
||||
m_compositor = new QWasmCompositor(this);
|
||||
m_eventTranslator = new QWasmEventTranslator(this);
|
||||
updateQScreenAndCanvasRenderSize();
|
||||
}
|
||||
|
||||
QWasmScreen::~QWasmScreen()
|
||||
@ -57,6 +60,31 @@ QWasmScreen::~QWasmScreen()
|
||||
|
||||
}
|
||||
|
||||
QWasmScreen *QWasmScreen::get(QPlatformScreen *screen)
|
||||
{
|
||||
return static_cast<QWasmScreen *>(screen);
|
||||
}
|
||||
|
||||
QWasmScreen *QWasmScreen::get(QScreen *screen)
|
||||
{
|
||||
return get(screen->handle());
|
||||
}
|
||||
|
||||
QWasmCompositor *QWasmScreen::compositor()
|
||||
{
|
||||
return m_compositor;
|
||||
}
|
||||
|
||||
QWasmEventTranslator *QWasmScreen::eventTranslator()
|
||||
{
|
||||
return m_eventTranslator;
|
||||
}
|
||||
|
||||
QString QWasmScreen::canvasId() const
|
||||
{
|
||||
return m_canvasId;
|
||||
}
|
||||
|
||||
QRect QWasmScreen::geometry() const
|
||||
{
|
||||
return m_geometry;
|
||||
@ -82,6 +110,11 @@ qreal QWasmScreen::devicePixelRatio() const
|
||||
return qreal(htmlWindowDpr);
|
||||
}
|
||||
|
||||
QString QWasmScreen::name() const
|
||||
{
|
||||
return m_canvasId;
|
||||
}
|
||||
|
||||
QPlatformCursor *QWasmScreen::cursor() const
|
||||
{
|
||||
return const_cast<QWasmCursor *>(&m_cursor);
|
||||
@ -114,4 +147,31 @@ void QWasmScreen::setGeometry(const QRect &rect)
|
||||
resizeMaximizedWindows();
|
||||
}
|
||||
|
||||
void QWasmScreen::updateQScreenAndCanvasRenderSize()
|
||||
{
|
||||
// The HTML canvas has two sizes: the CSS size and the canvas render size.
|
||||
// The CSS size is determined according to standard CSS rules, while the
|
||||
// render size is set using the "width" and "height" attributes. The render
|
||||
// size must be set manually and is not auto-updated on CSS size change.
|
||||
// Setting the render size to a value larger than the CSS size enables high-dpi
|
||||
// rendering.
|
||||
|
||||
QByteArray canvasId = m_canvasId.toUtf8();
|
||||
double css_width;
|
||||
double css_height;
|
||||
emscripten_get_element_css_size(canvasId.constData(), &css_width, &css_height);
|
||||
QSizeF cssSize(css_width, css_height);
|
||||
|
||||
QSizeF canvasSize = cssSize * devicePixelRatio();
|
||||
emscripten::val canvas = emscripten::val::global(canvasId.constData());
|
||||
canvas.set("width", canvasSize.width());
|
||||
canvas.set("height", canvasSize.height());
|
||||
|
||||
emscripten::val rect = canvas.call<emscripten::val>("getBoundingClientRect");
|
||||
QPoint position(rect["left"].as<int>(), rect["top"].as<int>());
|
||||
|
||||
setGeometry(QRect(position, cssSize.toSize()));
|
||||
m_compositor->redrawWindowContent();
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -43,20 +43,28 @@ class QPlatformOpenGLContext;
|
||||
class QWasmWindow;
|
||||
class QWasmBackingStore;
|
||||
class QWasmCompositor;
|
||||
class QWasmEventTranslator;
|
||||
class QOpenGLContext;
|
||||
|
||||
class QWasmScreen : public QObject, public QPlatformScreen
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
QWasmScreen(QWasmCompositor *compositor);
|
||||
QWasmScreen(const QString &canvasId);
|
||||
~QWasmScreen();
|
||||
|
||||
static QWasmScreen *get(QPlatformScreen *screen);
|
||||
static QWasmScreen *get(QScreen *screen);
|
||||
QString canvasId() const;
|
||||
|
||||
QWasmCompositor *compositor();
|
||||
QWasmEventTranslator *eventTranslator();
|
||||
|
||||
QRect geometry() const override;
|
||||
int depth() const override;
|
||||
QImage::Format format() const override;
|
||||
qreal devicePixelRatio() const override;
|
||||
QString name() const override;
|
||||
QPlatformCursor *cursor() const override;
|
||||
|
||||
void resizeMaximizedWindows();
|
||||
@ -64,17 +72,18 @@ public:
|
||||
QWindow *topLevelAt(const QPoint &p) const override;
|
||||
|
||||
void invalidateSize();
|
||||
void updateQScreenAndCanvasRenderSize();
|
||||
|
||||
public slots:
|
||||
void setGeometry(const QRect &rect);
|
||||
protected:
|
||||
|
||||
private:
|
||||
QWasmCompositor *m_compositor;
|
||||
|
||||
QString m_canvasId;
|
||||
QWasmCompositor *m_compositor = nullptr;
|
||||
QWasmEventTranslator *m_eventTranslator = nullptr;
|
||||
QRect m_geometry = QRect(0, 0, 100, 100);
|
||||
int m_depth;
|
||||
QImage::Format m_format;
|
||||
int m_depth = 32;
|
||||
QImage::Format m_format = QImage::Format_RGB32;
|
||||
QWasmCursor m_cursor;
|
||||
};
|
||||
|
||||
|
@ -7,27 +7,32 @@
|
||||
<style>
|
||||
html, body { padding: 0; margin : 0; overflow:hidden; height: 100% }
|
||||
/* the canvas *must not* have any border or padding, or mouse coords will be wrong */
|
||||
canvas { border: 0px none; background-color: white; height:100%; width:100%; }
|
||||
canvas { border: 0px none; background-color: white; height:100%; width:100%; }
|
||||
/* The contenteditable property is set to true for the canvas in order to support
|
||||
clipboard events. Hide the resulting focus frame and set the cursor back to
|
||||
the default cursor. */
|
||||
canvas { outline: 0px solid transparent; cursor:default }
|
||||
</style>
|
||||
</head>
|
||||
<body onload="init()">
|
||||
<figure style="overflow:visible;" id="spinner">
|
||||
<figure style="overflow:visible;" id="qtspinner">
|
||||
<center style="margin-top:1.5em; line-height:150%">
|
||||
<img src="qtlogo.svg"; width=320; height=200; style="display:block"> </img>
|
||||
<strong>Qt for WebAssembly: APPNAME</strong>
|
||||
<div id="status"></div>
|
||||
<div id="qtstatus"></div>
|
||||
<noscript>JavaScript is disabled. Please enable JavaScript to use this application.</noscript>
|
||||
</center>
|
||||
</figure>
|
||||
<canvas id="canvas" oncontextmenu="event.preventDefault()"></canvas>
|
||||
<canvas id="qtcanvas" oncontextmenu="event.preventDefault()" contenteditable="true"></canvas>
|
||||
|
||||
<script type='text/javascript'>
|
||||
function init() {
|
||||
var spinner = document.getElementById('spinner');
|
||||
var canvas = document.getElementById('canvas');
|
||||
var status = document.getElementById('status')
|
||||
var spinner = document.getElementById('qtspinner');
|
||||
var canvas = document.getElementById('qtcanvas');
|
||||
var status = document.getElementById('qtstatus')
|
||||
|
||||
var qtLoader = QtLoader({
|
||||
canvasElements : [canvas],
|
||||
showLoader: function(loaderStatus) {
|
||||
spinner.style.display = 'block';
|
||||
canvas.style.display = 'none';
|
||||
@ -50,7 +55,6 @@
|
||||
showCanvas: function() {
|
||||
spinner.style.display = 'none';
|
||||
canvas.style.display = 'block';
|
||||
return canvas;
|
||||
},
|
||||
});
|
||||
qtLoader.loadEmscriptenModule("APPNAME");
|
||||
|
@ -55,9 +55,8 @@ bool QAppleTestLogger::debugLoggingEnabled()
|
||||
return os_log_type_enabled(OS_LOG_DEFAULT, OS_LOG_TYPE_DEBUG);
|
||||
}
|
||||
|
||||
QAppleTestLogger::QAppleTestLogger(QAbstractTestLogger *logger)
|
||||
QAppleTestLogger::QAppleTestLogger()
|
||||
: QAbstractTestLogger(nullptr)
|
||||
, m_logger(logger)
|
||||
{
|
||||
}
|
||||
|
||||
@ -65,6 +64,8 @@ static QAppleLogActivity testFunctionActivity;
|
||||
|
||||
void QAppleTestLogger::enterTestFunction(const char *function)
|
||||
{
|
||||
Q_UNUSED(function);
|
||||
|
||||
// Re-create activity each time
|
||||
testFunctionActivity = QT_APPLE_LOG_ACTIVITY("Running test function").enter();
|
||||
|
||||
@ -73,15 +74,12 @@ void QAppleTestLogger::enterTestFunction(const char *function)
|
||||
QString identifier = QString::fromLatin1(testIdentifier.data());
|
||||
QMessageLogContext context(nullptr, 0, nullptr, "qt.test.enter");
|
||||
QString message = identifier;
|
||||
if (AppleUnifiedLogger::messageHandler(QtDebugMsg, context, message, identifier))
|
||||
return; // AUL already printed to stderr
|
||||
|
||||
m_logger->enterTestFunction(function);
|
||||
AppleUnifiedLogger::messageHandler(QtDebugMsg, context, message, identifier);
|
||||
}
|
||||
|
||||
void QAppleTestLogger::leaveTestFunction()
|
||||
{
|
||||
m_logger->leaveTestFunction();
|
||||
testFunctionActivity.leave();
|
||||
}
|
||||
|
||||
@ -134,18 +132,12 @@ void QAppleTestLogger::addIncident(IncidentTypes type, const char *description,
|
||||
if (qstrlen(description))
|
||||
message += QLatin1Char('\n') % QString::fromLatin1(description);
|
||||
|
||||
if (AppleUnifiedLogger::messageHandler(incidentClassification.first, context, message, subsystem))
|
||||
return; // AUL already printed to stderr
|
||||
|
||||
m_logger->addIncident(type, description, file, line);
|
||||
AppleUnifiedLogger::messageHandler(incidentClassification.first, context, message, subsystem);
|
||||
}
|
||||
|
||||
void QAppleTestLogger::addMessage(QtMsgType type, const QMessageLogContext &context, const QString &message)
|
||||
{
|
||||
if (AppleUnifiedLogger::messageHandler(type, context, message))
|
||||
return; // AUL already printed to stderr
|
||||
|
||||
m_logger->addMessage(type, context, message);
|
||||
AppleUnifiedLogger::messageHandler(type, context, message);
|
||||
}
|
||||
|
||||
#endif // QT_USE_APPLE_UNIFIED_LOGGING
|
||||
|
@ -63,12 +63,7 @@ class QAppleTestLogger : public QAbstractTestLogger
|
||||
public:
|
||||
static bool debugLoggingEnabled();
|
||||
|
||||
QAppleTestLogger(QAbstractTestLogger *logger);
|
||||
|
||||
void startLogging() override
|
||||
{ m_logger->startLogging(); }
|
||||
void stopLogging() override
|
||||
{ m_logger->stopLogging(); }
|
||||
QAppleTestLogger();
|
||||
|
||||
void enterTestFunction(const char *function) override;
|
||||
void leaveTestFunction() override;
|
||||
@ -77,16 +72,12 @@ public:
|
||||
const char *file = 0, int line = 0) override;
|
||||
void addMessage(QtMsgType, const QMessageLogContext &,
|
||||
const QString &) override;
|
||||
|
||||
void addBenchmarkResult(const QBenchmarkResult &result) override
|
||||
{ m_logger->addBenchmarkResult(result); }
|
||||
|
||||
void addMessage(MessageTypes type, const QString &message,
|
||||
const char *file = 0, int line = 0) override
|
||||
{ m_logger->addMessage(type, message, file, line); }
|
||||
{ Q_UNUSED(type); Q_UNUSED(message); Q_UNUSED(file); Q_UNUSED(line); Q_UNREACHABLE(); }
|
||||
|
||||
private:
|
||||
QScopedPointer<QAbstractTestLogger> m_logger;
|
||||
void addBenchmarkResult(const QBenchmarkResult &result) override
|
||||
{ Q_UNUSED(result); }
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -78,6 +78,10 @@
|
||||
#include <QtTest/private/qtestutil_macos_p.h>
|
||||
#endif
|
||||
|
||||
#if defined(Q_OS_DARWIN)
|
||||
#include <QtTest/private/qappletestlogger_p.h>
|
||||
#endif
|
||||
|
||||
#include <cmath>
|
||||
#include <numeric>
|
||||
#include <algorithm>
|
||||
@ -511,7 +515,7 @@ static int qToInt(const char *str)
|
||||
|
||||
Q_TESTLIB_EXPORT void qtest_qParseArgs(int argc, const char *const argv[], bool qml)
|
||||
{
|
||||
QTestLog::LogMode logFormat = QTestLog::Plain;
|
||||
int logFormat = -1; // Not set
|
||||
const char *logFilename = 0;
|
||||
|
||||
QTest::testFunctions.clear();
|
||||
@ -679,7 +683,7 @@ Q_TESTLIB_EXPORT void qtest_qParseArgs(int argc, const char *const argv[], bool
|
||||
fprintf(stderr, "only one logger can log to stdout\n");
|
||||
exit(1);
|
||||
}
|
||||
QTestLog::addLogger(logFormat, filename);
|
||||
QTestLog::addLogger(QTestLog::LogMode(logFormat), filename);
|
||||
}
|
||||
delete [] filename;
|
||||
delete [] format;
|
||||
@ -841,10 +845,25 @@ Q_TESTLIB_EXPORT void qtest_qParseArgs(int argc, const char *const argv[], bool
|
||||
QTestLog::setInstalledTestCoverage(installedTestCoverage);
|
||||
|
||||
// If no loggers were created by the long version of the -o command-line
|
||||
// option, create a logger using whatever filename and format were
|
||||
// set using the old-style command-line options.
|
||||
if (QTestLog::loggerCount() == 0)
|
||||
QTestLog::addLogger(logFormat, logFilename);
|
||||
// option, but a logger was requested via the old-style option, add it.
|
||||
const bool explicitLoggerRequested = logFormat != -1;
|
||||
if (QTestLog::loggerCount() == 0 && explicitLoggerRequested)
|
||||
QTestLog::addLogger(QTestLog::LogMode(logFormat), logFilename);
|
||||
|
||||
bool addFallbackLogger = !explicitLoggerRequested;
|
||||
|
||||
#if defined(QT_USE_APPLE_UNIFIED_LOGGING)
|
||||
// Any explicitly requested loggers will be added by now, so we can check if they use stdout
|
||||
const bool safeToAddAppleLogger = !AppleUnifiedLogger::willMirrorToStderr() || !QTestLog::loggerUsingStdout();
|
||||
if (safeToAddAppleLogger && QAppleTestLogger::debugLoggingEnabled()) {
|
||||
QTestLog::addLogger(QTestLog::Apple, nullptr);
|
||||
if (AppleUnifiedLogger::willMirrorToStderr() && !logFilename)
|
||||
addFallbackLogger = false; // Prevent plain test logger fallback below
|
||||
}
|
||||
#endif
|
||||
|
||||
if (addFallbackLogger)
|
||||
QTestLog::addLogger(QTestLog::Plain, logFilename);
|
||||
}
|
||||
|
||||
// Temporary, backwards compatibility, until qtdeclarative's use of it is converted
|
||||
@ -2171,13 +2190,12 @@ QString QTest::qFindTestData(const QString& base, const char *file, int line, co
|
||||
if (found.isEmpty()) {
|
||||
const char *testObjectName = QTestResult::currentTestObjectName();
|
||||
if (testObjectName) {
|
||||
QString testsPath = QLibraryInfo::location(QLibraryInfo::TestsPath);
|
||||
QString candidate = QString::fromLatin1("%1/%2/%3")
|
||||
const QString testsPath = QLibraryInfo::location(QLibraryInfo::TestsPath);
|
||||
const QString candidate = QString::fromLatin1("%1/%2/%3")
|
||||
.arg(testsPath, QFile::decodeName(testObjectName).toLower(), base);
|
||||
if (QFileInfo::exists(candidate)) {
|
||||
found = candidate;
|
||||
}
|
||||
else if (QTestLog::verboseLevel() >= 2) {
|
||||
} else if (QTestLog::verboseLevel() >= 2) {
|
||||
QTestLog::info(qPrintable(
|
||||
QString::fromLatin1("testdata %1 not found in tests install path [%2]; "
|
||||
"checking next location")
|
||||
@ -2199,11 +2217,10 @@ QString QTest::qFindTestData(const QString& base, const char *file, int line, co
|
||||
}
|
||||
|
||||
const QString canonicalPath = srcdir.canonicalFilePath();
|
||||
QString candidate = QString::fromLatin1("%1/%2").arg(canonicalPath, base);
|
||||
const QString candidate = QString::fromLatin1("%1/%2").arg(canonicalPath, base);
|
||||
if (!canonicalPath.isEmpty() && QFileInfo::exists(candidate)) {
|
||||
found = candidate;
|
||||
}
|
||||
else if (QTestLog::verboseLevel() >= 2) {
|
||||
} else if (QTestLog::verboseLevel() >= 2) {
|
||||
QTestLog::info(qPrintable(
|
||||
QString::fromLatin1("testdata %1 not found relative to source path [%2]")
|
||||
.arg(base, QDir::toNativeSeparators(candidate))),
|
||||
@ -2213,31 +2230,48 @@ QString QTest::qFindTestData(const QString& base, const char *file, int line, co
|
||||
|
||||
// 4. Try resources
|
||||
if (found.isEmpty()) {
|
||||
QString candidate = QString::fromLatin1(":/%1").arg(base);
|
||||
if (QFileInfo::exists(candidate))
|
||||
const QString candidate = QString::fromLatin1(":/%1").arg(base);
|
||||
if (QFileInfo::exists(candidate)) {
|
||||
found = candidate;
|
||||
} else if (QTestLog::verboseLevel() >= 2) {
|
||||
QTestLog::info(qPrintable(
|
||||
QString::fromLatin1("testdata %1 not found in resources [%2]")
|
||||
.arg(base, QDir::toNativeSeparators(candidate))),
|
||||
file, line);
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Try current directory
|
||||
if (found.isEmpty()) {
|
||||
const QString candidate = QDir::currentPath() + QLatin1Char('/') + base;
|
||||
if (QFileInfo::exists(candidate))
|
||||
if (QFileInfo::exists(candidate)) {
|
||||
found = candidate;
|
||||
} else if (QTestLog::verboseLevel() >= 2) {
|
||||
QTestLog::info(qPrintable(
|
||||
QString::fromLatin1("testdata %1 not found in current directory [%2]")
|
||||
.arg(base, QDir::toNativeSeparators(candidate))),
|
||||
file, line);
|
||||
}
|
||||
}
|
||||
|
||||
// 6. Try main source directory
|
||||
if (found.isEmpty()) {
|
||||
QString candidate = QTest::mainSourcePath % QLatin1Char('/') % base;
|
||||
if (QFileInfo::exists(candidate))
|
||||
const QString candidate = QTest::mainSourcePath % QLatin1Char('/') % base;
|
||||
if (QFileInfo::exists(candidate)) {
|
||||
found = candidate;
|
||||
} else if (QTestLog::verboseLevel() >= 2) {
|
||||
QTestLog::info(qPrintable(
|
||||
QString::fromLatin1("testdata %1 not found in main source directory [%2]")
|
||||
.arg(base, QDir::toNativeSeparators(candidate))),
|
||||
file, line);
|
||||
}
|
||||
}
|
||||
|
||||
if (found.isEmpty()) {
|
||||
QTest::qWarn(qPrintable(
|
||||
QString::fromLatin1("testdata %1 could not be located!").arg(base)),
|
||||
file, line);
|
||||
}
|
||||
else if (QTestLog::verboseLevel() >= 1) {
|
||||
} else if (QTestLog::verboseLevel() >= 1) {
|
||||
QTestLog::info(qPrintable(
|
||||
QString::fromLatin1("testdata %1 was located at %2").arg(base, QDir::toNativeSeparators(found))),
|
||||
file, line);
|
||||
|
@ -60,6 +60,7 @@
|
||||
#include <QtCore/qbytearray.h>
|
||||
#include <QtCore/QElapsedTimer>
|
||||
#include <QtCore/QVariant>
|
||||
#include <QtCore/qvector.h>
|
||||
#if QT_CONFIG(regularexpression)
|
||||
#include <QtCore/QRegularExpression>
|
||||
#endif
|
||||
@ -98,6 +99,8 @@ static void saveCoverageTool(const char * appname, bool testfailed, bool install
|
||||
static QElapsedTimer elapsedFunctionTime;
|
||||
static QElapsedTimer elapsedTotalTime;
|
||||
|
||||
#define FOREACH_TEST_LOGGER for (QAbstractTestLogger *logger : QTest::loggers)
|
||||
|
||||
namespace QTest {
|
||||
|
||||
int fails = 0;
|
||||
@ -165,109 +168,7 @@ namespace QTest {
|
||||
|
||||
static IgnoreResultList *ignoreResultList = 0;
|
||||
|
||||
struct LoggerList
|
||||
{
|
||||
QAbstractTestLogger *logger;
|
||||
LoggerList *next;
|
||||
};
|
||||
|
||||
class TestLoggers
|
||||
{
|
||||
public:
|
||||
static void addLogger(QAbstractTestLogger *logger)
|
||||
{
|
||||
LoggerList *l = new LoggerList;
|
||||
l->logger = logger;
|
||||
l->next = loggers;
|
||||
loggers = l;
|
||||
}
|
||||
|
||||
static void destroyLoggers()
|
||||
{
|
||||
while (loggers) {
|
||||
LoggerList *l = loggers;
|
||||
loggers = loggers->next;
|
||||
delete l->logger;
|
||||
delete l;
|
||||
}
|
||||
}
|
||||
|
||||
#define FOREACH_LOGGER(operation) \
|
||||
LoggerList *l = loggers; \
|
||||
while (l) { \
|
||||
QAbstractTestLogger *logger = l->logger; \
|
||||
Q_UNUSED(logger); \
|
||||
operation; \
|
||||
l = l->next; \
|
||||
}
|
||||
|
||||
static void startLogging()
|
||||
{
|
||||
FOREACH_LOGGER(logger->startLogging());
|
||||
}
|
||||
|
||||
static void stopLogging()
|
||||
{
|
||||
FOREACH_LOGGER(logger->stopLogging());
|
||||
}
|
||||
|
||||
static void enterTestFunction(const char *function)
|
||||
{
|
||||
FOREACH_LOGGER(logger->enterTestFunction(function));
|
||||
}
|
||||
|
||||
static void leaveTestFunction()
|
||||
{
|
||||
FOREACH_LOGGER(logger->leaveTestFunction());
|
||||
}
|
||||
|
||||
static void enterTestData(QTestData *data)
|
||||
{
|
||||
FOREACH_LOGGER(logger->enterTestData(data));
|
||||
}
|
||||
|
||||
static void addIncident(QAbstractTestLogger::IncidentTypes type, const char *description,
|
||||
const char *file = 0, int line = 0)
|
||||
{
|
||||
FOREACH_LOGGER(logger->addIncident(type, description, file, line));
|
||||
}
|
||||
|
||||
static void addBenchmarkResult(const QBenchmarkResult &result)
|
||||
{
|
||||
FOREACH_LOGGER(logger->addBenchmarkResult(result));
|
||||
}
|
||||
|
||||
static void addMessage(QtMsgType type, const QMessageLogContext &context,
|
||||
const QString &message)
|
||||
{
|
||||
FOREACH_LOGGER(logger->addMessage(type, context, message));
|
||||
}
|
||||
|
||||
static void addMessage(QAbstractTestLogger::MessageTypes type, const QString &message,
|
||||
const char *file = 0, int line = 0)
|
||||
{
|
||||
FOREACH_LOGGER(logger->addMessage(type, message, file, line));
|
||||
}
|
||||
|
||||
static void outputString(const char *msg)
|
||||
{
|
||||
FOREACH_LOGGER(logger->outputString(msg));
|
||||
}
|
||||
|
||||
static int loggerCount()
|
||||
{
|
||||
int count = 0;
|
||||
FOREACH_LOGGER(++count);
|
||||
return count;
|
||||
}
|
||||
|
||||
private:
|
||||
static LoggerList *loggers;
|
||||
};
|
||||
|
||||
#undef FOREACH_LOGGER
|
||||
|
||||
LoggerList *TestLoggers::loggers = 0;
|
||||
static QVector<QAbstractTestLogger*> loggers;
|
||||
static bool loggerUsingStdout = false;
|
||||
|
||||
static int verbosity = 0;
|
||||
@ -306,10 +207,10 @@ namespace QTest {
|
||||
{
|
||||
static QBasicAtomicInt counter = Q_BASIC_ATOMIC_INITIALIZER(QTest::maxWarnings);
|
||||
|
||||
if (QTest::TestLoggers::loggerCount() == 0) {
|
||||
if (QTestLog::loggerCount() == 0) {
|
||||
// if this goes wrong, something is seriously broken.
|
||||
qInstallMessageHandler(oldMessageHandler);
|
||||
QTEST_ASSERT(QTest::TestLoggers::loggerCount() != 0);
|
||||
QTEST_ASSERT(QTestLog::loggerCount() != 0);
|
||||
}
|
||||
|
||||
if (handleIgnoredMessage(type, message)) {
|
||||
@ -322,13 +223,16 @@ namespace QTest {
|
||||
return;
|
||||
|
||||
if (!counter.deref()) {
|
||||
QTest::TestLoggers::addMessage(QAbstractTestLogger::QSystem,
|
||||
FOREACH_TEST_LOGGER {
|
||||
logger->addMessage(QAbstractTestLogger::QSystem,
|
||||
QStringLiteral("Maximum amount of warnings exceeded. Use -maxwarnings to override."));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
QTest::TestLoggers::addMessage(type, context, message);
|
||||
FOREACH_TEST_LOGGER
|
||||
logger->addMessage(type, context, message);
|
||||
|
||||
if (type == QtFatalMsg) {
|
||||
/* Right now, we're inside the custom message handler and we're
|
||||
@ -351,13 +255,16 @@ void QTestLog::enterTestFunction(const char* function)
|
||||
|
||||
QTEST_ASSERT(function);
|
||||
|
||||
QTest::TestLoggers::enterTestFunction(function);
|
||||
FOREACH_TEST_LOGGER
|
||||
logger->enterTestFunction(function);
|
||||
}
|
||||
|
||||
void QTestLog::enterTestData(QTestData *data)
|
||||
{
|
||||
QTEST_ASSERT(data);
|
||||
QTest::TestLoggers::enterTestData(data);
|
||||
|
||||
FOREACH_TEST_LOGGER
|
||||
logger->enterTestData(data);
|
||||
}
|
||||
|
||||
int QTestLog::unhandledIgnoreMessages()
|
||||
@ -376,7 +283,8 @@ void QTestLog::leaveTestFunction()
|
||||
if (printAvailableTags)
|
||||
return;
|
||||
|
||||
QTest::TestLoggers::leaveTestFunction();
|
||||
FOREACH_TEST_LOGGER
|
||||
logger->leaveTestFunction();
|
||||
}
|
||||
|
||||
void QTestLog::printUnhandledIgnoreMessages()
|
||||
@ -391,7 +299,8 @@ void QTestLog::printUnhandledIgnoreMessages()
|
||||
message = QStringLiteral("Did not receive any message matching: \"") + list->pattern.toRegularExpression().pattern() + QLatin1Char('"');
|
||||
#endif
|
||||
}
|
||||
QTest::TestLoggers::addMessage(QAbstractTestLogger::Info, message);
|
||||
FOREACH_TEST_LOGGER
|
||||
logger->addMessage(QAbstractTestLogger::Info, message);
|
||||
|
||||
list = list->next;
|
||||
}
|
||||
@ -411,7 +320,8 @@ void QTestLog::addPass(const char *msg)
|
||||
|
||||
++QTest::passes;
|
||||
|
||||
QTest::TestLoggers::addIncident(QAbstractTestLogger::Pass, msg);
|
||||
FOREACH_TEST_LOGGER
|
||||
logger->addIncident(QAbstractTestLogger::Pass, msg);
|
||||
}
|
||||
|
||||
void QTestLog::addFail(const char *msg, const char *file, int line)
|
||||
@ -420,7 +330,8 @@ void QTestLog::addFail(const char *msg, const char *file, int line)
|
||||
|
||||
++QTest::fails;
|
||||
|
||||
QTest::TestLoggers::addIncident(QAbstractTestLogger::Fail, msg, file, line);
|
||||
FOREACH_TEST_LOGGER
|
||||
logger->addIncident(QAbstractTestLogger::Fail, msg, file, line);
|
||||
}
|
||||
|
||||
void QTestLog::addXFail(const char *msg, const char *file, int line)
|
||||
@ -428,7 +339,8 @@ void QTestLog::addXFail(const char *msg, const char *file, int line)
|
||||
QTEST_ASSERT(msg);
|
||||
QTEST_ASSERT(file);
|
||||
|
||||
QTest::TestLoggers::addIncident(QAbstractTestLogger::XFail, msg, file, line);
|
||||
FOREACH_TEST_LOGGER
|
||||
logger->addIncident(QAbstractTestLogger::XFail, msg, file, line);
|
||||
}
|
||||
|
||||
void QTestLog::addXPass(const char *msg, const char *file, int line)
|
||||
@ -438,7 +350,8 @@ void QTestLog::addXPass(const char *msg, const char *file, int line)
|
||||
|
||||
++QTest::fails;
|
||||
|
||||
QTest::TestLoggers::addIncident(QAbstractTestLogger::XPass, msg, file, line);
|
||||
FOREACH_TEST_LOGGER
|
||||
logger->addIncident(QAbstractTestLogger::XPass, msg, file, line);
|
||||
}
|
||||
|
||||
void QTestLog::addBPass(const char *msg)
|
||||
@ -447,7 +360,8 @@ void QTestLog::addBPass(const char *msg)
|
||||
|
||||
++QTest::blacklists;
|
||||
|
||||
QTest::TestLoggers::addIncident(QAbstractTestLogger::BlacklistedPass, msg);
|
||||
FOREACH_TEST_LOGGER
|
||||
logger->addIncident(QAbstractTestLogger::BlacklistedPass, msg);
|
||||
}
|
||||
|
||||
void QTestLog::addBFail(const char *msg, const char *file, int line)
|
||||
@ -457,7 +371,8 @@ void QTestLog::addBFail(const char *msg, const char *file, int line)
|
||||
|
||||
++QTest::blacklists;
|
||||
|
||||
QTest::TestLoggers::addIncident(QAbstractTestLogger::BlacklistedFail, msg, file, line);
|
||||
FOREACH_TEST_LOGGER
|
||||
logger->addIncident(QAbstractTestLogger::BlacklistedFail, msg, file, line);
|
||||
}
|
||||
|
||||
void QTestLog::addBXPass(const char *msg, const char *file, int line)
|
||||
@ -467,7 +382,8 @@ void QTestLog::addBXPass(const char *msg, const char *file, int line)
|
||||
|
||||
++QTest::blacklists;
|
||||
|
||||
QTest::TestLoggers::addIncident(QAbstractTestLogger::BlacklistedXPass, msg, file, line);
|
||||
FOREACH_TEST_LOGGER
|
||||
logger->addIncident(QAbstractTestLogger::BlacklistedXPass, msg, file, line);
|
||||
}
|
||||
|
||||
void QTestLog::addBXFail(const char *msg, const char *file, int line)
|
||||
@ -477,7 +393,8 @@ void QTestLog::addBXFail(const char *msg, const char *file, int line)
|
||||
|
||||
++QTest::blacklists;
|
||||
|
||||
QTest::TestLoggers::addIncident(QAbstractTestLogger::BlacklistedXFail, msg, file, line);
|
||||
FOREACH_TEST_LOGGER
|
||||
logger->addIncident(QAbstractTestLogger::BlacklistedXFail, msg, file, line);
|
||||
}
|
||||
|
||||
void QTestLog::addSkip(const char *msg, const char *file, int line)
|
||||
@ -487,27 +404,33 @@ void QTestLog::addSkip(const char *msg, const char *file, int line)
|
||||
|
||||
++QTest::skips;
|
||||
|
||||
QTest::TestLoggers::addMessage(QAbstractTestLogger::Skip, QString::fromUtf8(msg), file, line);
|
||||
FOREACH_TEST_LOGGER
|
||||
logger->addMessage(QAbstractTestLogger::Skip, QString::fromUtf8(msg), file, line);
|
||||
}
|
||||
|
||||
void QTestLog::addBenchmarkResult(const QBenchmarkResult &result)
|
||||
{
|
||||
QTest::TestLoggers::addBenchmarkResult(result);
|
||||
FOREACH_TEST_LOGGER
|
||||
logger->addBenchmarkResult(result);
|
||||
}
|
||||
|
||||
void QTestLog::startLogging()
|
||||
{
|
||||
elapsedTotalTime.start();
|
||||
elapsedFunctionTime.start();
|
||||
QTest::TestLoggers::startLogging();
|
||||
FOREACH_TEST_LOGGER
|
||||
logger->startLogging();
|
||||
QTest::oldMessageHandler = qInstallMessageHandler(QTest::messageHandler);
|
||||
}
|
||||
|
||||
void QTestLog::stopLogging()
|
||||
{
|
||||
qInstallMessageHandler(QTest::oldMessageHandler);
|
||||
QTest::TestLoggers::stopLogging();
|
||||
QTest::TestLoggers::destroyLoggers();
|
||||
FOREACH_TEST_LOGGER {
|
||||
logger->stopLogging();
|
||||
delete logger;
|
||||
}
|
||||
QTest::loggers.clear();
|
||||
QTest::loggerUsingStdout = false;
|
||||
saveCoverageTool(QTestResult::currentAppName(), failCount() != 0, QTestLog::installedTestCoverage());
|
||||
}
|
||||
@ -542,6 +465,11 @@ void QTestLog::addLogger(LogMode mode, const char *filename)
|
||||
case QTestLog::TAP:
|
||||
logger = new QTapTestLogger(filename);
|
||||
break;
|
||||
#if defined(QT_USE_APPLE_UNIFIED_LOGGING)
|
||||
case QTestLog::Apple:
|
||||
logger = new QAppleTestLogger;
|
||||
break;
|
||||
#endif
|
||||
#if defined(HAVE_XCTEST)
|
||||
case QTestLog::XCTest:
|
||||
logger = new QXcodeTestLogger;
|
||||
@ -549,21 +477,13 @@ void QTestLog::addLogger(LogMode mode, const char *filename)
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(QT_USE_APPLE_UNIFIED_LOGGING)
|
||||
// Logger that also feeds messages to AUL. It needs to wrap the existing
|
||||
// logger, as it needs to be able to short circuit the existing logger
|
||||
// in case AUL prints to stderr.
|
||||
if (QAppleTestLogger::debugLoggingEnabled())
|
||||
logger = new QAppleTestLogger(logger);
|
||||
#endif
|
||||
|
||||
QTEST_ASSERT(logger);
|
||||
QTest::TestLoggers::addLogger(logger);
|
||||
QTest::loggers.append(logger);
|
||||
}
|
||||
|
||||
int QTestLog::loggerCount()
|
||||
{
|
||||
return QTest::TestLoggers::loggerCount();
|
||||
return QTest::loggers.size();
|
||||
}
|
||||
|
||||
bool QTestLog::loggerUsingStdout()
|
||||
@ -575,15 +495,16 @@ void QTestLog::warn(const char *msg, const char *file, int line)
|
||||
{
|
||||
QTEST_ASSERT(msg);
|
||||
|
||||
if (QTest::TestLoggers::loggerCount() > 0)
|
||||
QTest::TestLoggers::addMessage(QAbstractTestLogger::Warn, QString::fromUtf8(msg), file, line);
|
||||
FOREACH_TEST_LOGGER
|
||||
logger->addMessage(QAbstractTestLogger::Warn, QString::fromUtf8(msg), file, line);
|
||||
}
|
||||
|
||||
void QTestLog::info(const char *msg, const char *file, int line)
|
||||
{
|
||||
QTEST_ASSERT(msg);
|
||||
|
||||
QTest::TestLoggers::addMessage(QAbstractTestLogger::Info, QString::fromUtf8(msg), file, line);
|
||||
FOREACH_TEST_LOGGER
|
||||
logger->addMessage(QAbstractTestLogger::Info, QString::fromUtf8(msg), file, line);
|
||||
}
|
||||
|
||||
void QTestLog::setVerboseLevel(int level)
|
||||
|
@ -53,6 +53,10 @@
|
||||
|
||||
#include <QtTest/qttestglobal.h>
|
||||
|
||||
#if defined(Q_OS_DARWIN)
|
||||
#include <QtCore/private/qcore_mac_p.h>
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QBenchmarkResult;
|
||||
@ -63,9 +67,12 @@ class Q_TESTLIB_EXPORT QTestLog
|
||||
{
|
||||
public:
|
||||
enum LogMode {
|
||||
Plain = 0, XML, LightXML, XunitXML, CSV, TeamCity, TAP,
|
||||
Plain = 0, XML, LightXML, XunitXML, CSV, TeamCity, TAP
|
||||
#if defined(QT_USE_APPLE_UNIFIED_LOGGING)
|
||||
, Apple
|
||||
#endif
|
||||
#if defined(HAVE_XCTEST)
|
||||
XCTest
|
||||
, XCTest
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -148,7 +148,7 @@ bool QDialogPrivate::canBeNativeDialog() const
|
||||
/*!
|
||||
\internal
|
||||
|
||||
Properly hides dialog and sets the \p resultCode
|
||||
Properly hides dialog and sets the \a resultCode.
|
||||
*/
|
||||
void QDialogPrivate::hide(int resultCode)
|
||||
{
|
||||
@ -164,8 +164,8 @@ void QDialogPrivate::hide(int resultCode)
|
||||
/*!
|
||||
\internal
|
||||
|
||||
Emits finished() signal with \p resultCode. If the \p dialogCode
|
||||
is equal to 0 emits rejected(), if the \p dialogCode is equal to
|
||||
Emits finished() signal with \a resultCode. If the \a dialogCode
|
||||
is equal to 0 emits rejected(), if the \a dialogCode is equal to
|
||||
1 emits accepted().
|
||||
*/
|
||||
void QDialogPrivate::finalize(int resultCode, int dialogCode)
|
||||
|
@ -2045,7 +2045,7 @@ void tst_QDir::detachingOperations()
|
||||
QCOMPARE(dir2.nameFilters(), nameFilters);
|
||||
QCOMPARE(dir2.sorting(), sorting);
|
||||
|
||||
dir2 = path1;
|
||||
dir2.setPath(path1);
|
||||
QCOMPARE(dir2.path(), path1);
|
||||
QCOMPARE(dir2.filter(), filter);
|
||||
QCOMPARE(dir2.nameFilters(), nameFilters);
|
||||
|
@ -10,7 +10,7 @@ SUBDIRS = lib \
|
||||
tst.depends += almostplugin
|
||||
SUBDIRS += almostplugin
|
||||
}
|
||||
macos:qtConfig(private_tests) {
|
||||
macos:qtConfig(private_tests):qtHaveModule(gui) {
|
||||
tst.depends += machtest
|
||||
SUBDIRS += machtest
|
||||
}
|
||||
|
@ -57,7 +57,6 @@ private Q_SLOTS:
|
||||
|
||||
void lookupTableConstructor();
|
||||
|
||||
void lookupTableStatic_data();
|
||||
void lookupTableStatic();
|
||||
void lookupTableDynamic();
|
||||
|
||||
@ -126,7 +125,7 @@ void tst_Hpack::bitstreamConstruction()
|
||||
// 'Read' some data back:
|
||||
for (int i = 0; i < size; ++i) {
|
||||
uchar bitPattern = 0;
|
||||
const auto bitsRead = in.peekBits(i * 8, 8, &bitPattern);
|
||||
const auto bitsRead = in.peekBits(quint64(i * 8), 8, &bitPattern);
|
||||
QVERIFY(bitsRead == 8);
|
||||
QVERIFY(bitPattern == bytes[i]);
|
||||
}
|
||||
@ -282,7 +281,7 @@ void tst_Hpack::bitstreamCompression()
|
||||
const auto start = QRandomGenerator::global()->bounded(uint(bytes.length()) / 2);
|
||||
auto end = start * 2;
|
||||
if (!end)
|
||||
end = bytes.length() / 2;
|
||||
end = unsigned(bytes.length() / 2);
|
||||
strings.push_back(bytes.substr(start, end - start));
|
||||
const auto &s = strings.back();
|
||||
totalStringBytes += s.size();
|
||||
@ -384,43 +383,21 @@ void tst_Hpack::lookupTableConstructor()
|
||||
}
|
||||
}
|
||||
|
||||
void tst_Hpack::lookupTableStatic_data()
|
||||
{
|
||||
QTest::addColumn<QByteArray>("expectedName");
|
||||
QTest::addColumn<QByteArray>("expectedValue");
|
||||
|
||||
// Some predefined fields to find
|
||||
// (they are always defined/required by HPACK).
|
||||
QTest::newRow(":authority|") << QByteArray(":authority") << QByteArray("");
|
||||
QTest::newRow(":method|GET") << QByteArray(":method") << QByteArray("GET");
|
||||
QTest::newRow(":method|POST") << QByteArray(":method") << QByteArray("POST");
|
||||
QTest::newRow(":path|/") << QByteArray(":path") << QByteArray("/");
|
||||
QTest::newRow(":path|/index.html") << QByteArray(":path") << QByteArray("/index.html");
|
||||
QTest::newRow(":scheme|http") << QByteArray(":scheme") << QByteArray("http");
|
||||
QTest::newRow(":scheme|https") << QByteArray(":scheme") << QByteArray("https");
|
||||
QTest::newRow(":status|200") << QByteArray(":status") << QByteArray("200");
|
||||
QTest::newRow(":status|204") << QByteArray(":status") << QByteArray("204");
|
||||
QTest::newRow(":status|206") << QByteArray(":status") << QByteArray("206");
|
||||
QTest::newRow(":status|304") << QByteArray(":status") << QByteArray("304");
|
||||
QTest::newRow(":status|400") << QByteArray(":status") << QByteArray("400");
|
||||
QTest::newRow(":status|404") << QByteArray(":status") << QByteArray("404");
|
||||
QTest::newRow(":status|500") << QByteArray(":status") << QByteArray("500");
|
||||
}
|
||||
|
||||
void tst_Hpack::lookupTableStatic()
|
||||
{
|
||||
const FieldLookupTable table(0, false /*all static, no need in 'search index'*/);
|
||||
|
||||
QFETCH(QByteArray, expectedName);
|
||||
QFETCH(QByteArray, expectedValue);
|
||||
|
||||
const quint32 index = table.indexOf(expectedName, expectedValue);
|
||||
QVERIFY(index != 0);
|
||||
|
||||
const auto &staticTable = FieldLookupTable::staticPart();
|
||||
QByteArray name, value;
|
||||
QVERIFY(table.field(index, &name, &value));
|
||||
QCOMPARE(name, expectedName);
|
||||
QCOMPARE(value, expectedValue);
|
||||
quint32 currentIndex = 1; // HPACK is indexing starting from 1.
|
||||
for (const HeaderField &field : staticTable) {
|
||||
const quint32 index = table.indexOf(field.name, field.value);
|
||||
QVERIFY(index != 0);
|
||||
QCOMPARE(index, currentIndex);
|
||||
QVERIFY(table.field(index, &name, &value));
|
||||
QCOMPARE(name, field.name);
|
||||
QCOMPARE(value, field.value);
|
||||
++currentIndex;
|
||||
}
|
||||
}
|
||||
|
||||
void tst_Hpack::lookupTableDynamic()
|
||||
|
@ -56,7 +56,7 @@ winrt|!qtHaveModule(gui)|!qtConfig(accessibility): SUBDIRS -= qaccessibility
|
||||
|
||||
!qtConfig(process): SUBDIRS -= qprocess_and_guieventloop
|
||||
|
||||
!mac: SUBDIRS -= \
|
||||
!macos|!qtHaveModule(gui): SUBDIRS -= \
|
||||
macgui \
|
||||
macnativeevents \
|
||||
macplist \
|
||||
|
Loading…
Reference in New Issue
Block a user