aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2018-10-30 08:13:57 +0100
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2018-10-30 08:14:00 +0100
commit8aa7bd47d35f9c6b699e4d4c8cc24911ba9443ff (patch)
tree7b7a928ef761e54e405f68436f5f8d51939ed497
parenta4f7ce5f65621de768510e11da5762c3c7b2a983 (diff)
parent6e2741e3e38c09a014efc9cb0079ef942ff54626 (diff)
Merge remote-tracking branch 'origin/5.12' into dev
-rw-r--r--README.pyside2.md62
-rw-r--r--README.shiboken2-generator.md36
-rw-r--r--README.shiboken2.md12
-rw-r--r--build_scripts/options.py55
-rw-r--r--missing_bindings.py14
-rw-r--r--sources/cmake_helpers/helpers.cmake15
-rw-r--r--sources/pyside2/PySide2/Qt3DCore/typesystem_3dcore.xml33
-rw-r--r--sources/pyside2/PySide2/Qt3DInput/typesystem_3dinput.xml17
-rw-r--r--sources/pyside2/PySide2/QtCore/CMakeLists.txt1
-rw-r--r--sources/pyside2/PySide2/QtCore/typesystem_core_common.xml27
-rw-r--r--sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml21
-rw-r--r--sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp6
-rw-r--r--sources/pyside2/PySide2/QtWidgets/typesystem_widgets_common.xml20
-rw-r--r--sources/pyside2/PySide2/typesystem_templates.xml20
-rw-r--r--sources/pyside2/cmake/Macros/PySideModules.cmake4
-rw-r--r--sources/pyside2/libpyside/CMakeLists.txt3
-rw-r--r--sources/pyside2/libpyside/dynamicqmetaobject.cpp908
-rw-r--r--sources/pyside2/libpyside/dynamicqmetaobject.h38
-rw-r--r--sources/pyside2/libpyside/globalreceiverv2.cpp10
-rw-r--r--sources/pyside2/libpyside/globalreceiverv2.h5
-rw-r--r--sources/pyside2/libpyside/pyside.cpp11
-rw-r--r--sources/pyside2/libpyside/pyside_p.h6
-rw-r--r--sources/pyside2/libpyside/pysideclassinfo.cpp7
-rw-r--r--sources/pyside2/libpyside/pysidemetafunction.cpp2
-rw-r--r--sources/pyside2/libpyside/pysideqflags.cpp2
-rw-r--r--sources/pyside2/libpyside/pysidesignal.cpp6
-rw-r--r--sources/pyside2/libpyside/pysideslot.cpp2
-rw-r--r--sources/pyside2/libpyside/pysideweakref.cpp2
-rw-r--r--sources/pyside2/libpyside/signalmanager.cpp44
-rw-r--r--sources/pyside2/tests/QtCore/qmetaobject_test.py6
-rw-r--r--sources/pyside2/tests/QtWidgets/qwidget_test.py23
-rw-r--r--sources/pyside2/tests/pysidetest/CMakeLists.txt5
-rw-r--r--sources/shiboken2/generator/generator.cpp15
-rw-r--r--sources/shiboken2/generator/shiboken2/cppgenerator.cpp16
-rw-r--r--sources/shiboken2/generator/shiboken2/headergenerator.cpp9
-rw-r--r--sources/shiboken2/libshiboken/basewrapper.cpp6
-rw-r--r--sources/shiboken2/libshiboken/basewrapper.h12
-rw-r--r--sources/shiboken2/libshiboken/pep384impl_doc.rst13
-rw-r--r--sources/shiboken2/libshiboken/sbkenum.cpp2
-rw-r--r--sources/shiboken2/libshiboken/voidptr.cpp2
-rw-r--r--sources/shiboken2/shibokenmodule/CMakeLists.txt5
-rw-r--r--sources/shiboken2/tests/minimalbinding/CMakeLists.txt5
-rw-r--r--sources/shiboken2/tests/otherbinding/CMakeLists.txt5
-rw-r--r--sources/shiboken2/tests/samplebinding/CMakeLists.txt5
-rw-r--r--sources/shiboken2/tests/smartbinding/CMakeLists.txt5
45 files changed, 704 insertions, 819 deletions
diff --git a/README.pyside2.md b/README.pyside2.md
index cde05940d..53f7bc9d0 100644
--- a/README.pyside2.md
+++ b/README.pyside2.md
@@ -2,52 +2,70 @@
### Introduction
-PySide is the [Python Qt bindings project](http://wiki.qt.io/PySide2), providing
-access to the complete Qt 5.x framework as well as to generator tools for rapidly
-generating bindings for any C++ libraries.
+PySide is the [Python Qt bindings project](http://wiki.qt.io/Qt_for_Python),
+providing access to the complete Qt 5.12+ framework as well as to generator
+tools for rapidly generating Python bindings for any C++ libraries.
The PySide project is developed in the open, with all facilities you'd expect
from any modern OSS project such as all code in a git repository and an open
design process. We welcome any contribution conforming to the
[Qt Contribution Agreement](https://www.qt.io/contributionagreement/).
+### Installation
-PySide 2 supports Qt5. For building, please read about
-[getting started](https://wiki.qt.io/PySide2_GettingStarted).
-Then download the sources by running
+Since the release of the [Technical Preview](https://blog.qt.io/blog/2018/06/13/qt-python-5-11-released/)
+it is possible to install via `pip`, both from Qt's servers
+and [PyPi](https://pypi.org/project/PySide2/):
- git clone https://code.qt.io/pyside/pyside-setup
-
-### Building
+ pip install PySide2
#### Dependencies
-PySide versions following 5.6 use a C++ parser based on
-[Clang](http://clang.org/). The Clang library (C-bindings), version 3.9 or
+PySide versions following 5.12 use a C++ parser based on
+[Clang](http://clang.org/). The Clang library (C-bindings), version 6.0 or
higher is required for building. Prebuilt versions of it can be downloaded from
[download.qt.io](http://download.qt.io/development_releases/prebuilt/libclang/).
After unpacking the archive, set the environment variable *LLVM_INSTALL_DIR* to
point to the folder containing the *include* and *lib* directories of Clang:
- 7z x .../libclang-release_39-linux-Rhel7.2-gcc5.3-x86_64.7z
+ 7z x .../libclang-release_60-linux-Rhel7.2-gcc5.3-x86_64-clazy.7z
export LLVM_INSTALL_DIR=$PWD/libclang
On Windows:
- 7z x .../libclang-release_39-windows-vs2015_64.7z
+ 7z x .../libclang-release_60-windows-vs2015_64-clazy.7z
SET LLVM_INSTALL_DIR=%CD%\libclang
-#### Build Instructions
+### Building from source
-You might consider using a virtual environment as described at
-[getting started](https://wiki.qt.io/PySide2_GettingStarted).
-You should be able to build:
+For building PySide2 from scratch, please read about
+[getting started](https://wiki.qt.io/Qt_for_Python/GettingStarted).
+This process will include getting the code:
+ git clone https://code.qt.io/pyside/pyside-setup
cd pyside-setup
- python setup.py install
+ git branch --track 5.12 origin/5.12
+ git checkout 5.12
+
+then install the dependencies, and following the instructions per platform.
+A common build command will look like:
+
+ python setup.py install --qmake=<path/to/qmake/> --jobs=8 --build-tests
+
+You can obtain more information about the options to build PySide
+and Shiboken in [our wiki](https://wiki.qt.io/Qt_for_Python/).
+
+### Documentation and Bugs
+
+You can find more information about the PySide2 module API in the
+[official Qt for Python documentation](https://doc.qt.io/qtforpython/).
+
+If you come across any issue, please file a bug report at our
+[JIRA tracker](https://bugreports.qt.io/projects/PYSIDE) following
+our [guidelines](https://wiki.qt.io/Qt_for_Python/Reporting_Bugs).
+
+### Community
-The setup script will try to find the location of the qmake tool of the Qt
-version to be used and the cmake build tool in the path. Non-standard
-locations can be specified by the *--qmake=path_to_qmake* or
-*--cmake=path_to_cmake* command line options.
+Check *#qt-pyside*, our official IRC channel on FreeNode,
+or contact us via our [mailing list](http://lists.qt-project.org/mailman/listinfo/pyside).
diff --git a/README.shiboken2-generator.md b/README.shiboken2-generator.md
index c71c6a8de..f29f40634 100644
--- a/README.shiboken2-generator.md
+++ b/README.shiboken2-generator.md
@@ -1 +1,37 @@
# shiboken2-generator
+
+Shiboken is the generator used by the Qt for Python project.
+It outputs C++ code for CPython extensions, which can be compiled
+and transformed into a Python module.
+
+C++ projects based on Qt can be wrapped, but also projects
+which are not related to Qt.
+
+## How does it work?
+
+Shiboken uses an API Extractor that does most of the job,
+but it requires a typesystem (XML file) to customize how the
+C++ classes/methods will be exposed to Python.
+
+The typesystem allows you to remove arguments from signatures,
+modify return types, inject code and add conversion rules
+from the C++ data types to Python data types, manipulate
+the ownership of the objects, etc.
+
+# Examples
+
+An example related to wrap a C++ library not depending on Qt
+can be found in our [repository](https://code.qt.io/cgit/pyside/pyside-setup.git/tree/examples/samplebinding).
+
+Additionally, you can find a couple of tests inside the
+[git repository](https://code.qt.io/cgit/pyside/pyside-setup.git/tree/sources/shiboken2/tests).
+
+For a more advanced case regarding extending a Qt/C++ application
+with Python bindings based on the idea of the PySide module,
+you can check the [scriptableapplication](https://code.qt.io/cgit/pyside/pyside-setup.git/tree/examples/scriptableapplication)
+example in our repository.
+
+# Documentation
+
+You can find more information about Shiboken in our
+[official documentation page](https://doc.qt.io/qtforpython/shiboken2/).
diff --git a/README.shiboken2.md b/README.shiboken2.md
index f98f63c57..d9cd32a40 100644
--- a/README.shiboken2.md
+++ b/README.shiboken2.md
@@ -1 +1,13 @@
# shiboken2 module
+
+The purpose of the shiboken2 Python module is to access information
+related to the binding generation that could be used to integrate
+C++ programs to Python, or even to get useful information to debug
+an application.
+
+Mostly the idea is to interact with Shiboken objects,
+where one can check if it is valid, or if the generated Python wrapper
+is invalid after the underlying C++ object has been destroyed.
+
+More information on the available functions can be found
+in our [official documentation](https://doc.qt.io/qtforpython/shiboken2/shibokenmodule.html)
diff --git a/build_scripts/options.py b/build_scripts/options.py
index daf3bb00e..3e3a63ca9 100644
--- a/build_scripts/options.py
+++ b/build_scripts/options.py
@@ -40,8 +40,13 @@
from __future__ import print_function
import sys
import os
+import warnings
+def _warn_multiple_option(option):
+ w = 'Option "{}" occurs multiple times on the command line.'.format(option)
+ warnings.warn(w)
+
class Options(object):
def __init__(self):
@@ -51,13 +56,13 @@ class Options(object):
def has_option(self, name):
""" Returns True if argument '--name' was passed on the command
line. """
- try:
- sys.argv.remove("--{}".format(name))
- self.dict[name] = True
- return True
- except ValueError:
- pass
- return False
+ option = '--' + name
+ count = sys.argv.count(option)
+ for i in range(count):
+ sys.argv.remove(option)
+ if count > 1:
+ _warn_multiple_option(option)
+ return count > 0
def option_value(self, name, remove=True):
"""
@@ -73,30 +78,36 @@ class Options(object):
:return: Either the option value or None.
"""
- for index, option in enumerate(sys.argv):
- if option == '--' + name:
- if index + 1 >= len(sys.argv):
- raise RuntimeError("The option {} requires a value".format(option))
- value = sys.argv[index + 1]
+ option = '--' + name
+ single_option_prefix = option + '='
+ value = None
+ for index in reversed(range(len(sys.argv))):
+ arg = sys.argv[index]
+ if arg == option:
+ if value:
+ _warn_multiple_option(option)
+ else:
+ if index + 1 >= len(sys.argv):
+ raise RuntimeError("The option {} requires a value".format(option))
+ value = sys.argv[index + 1]
if remove:
sys.argv[index:index + 2] = []
- self.dict[name] = value
- return value
-
- if option.startswith('--' + name + '='):
- value = option[len(name) + 3:]
+ elif arg.startswith(single_option_prefix):
+ if value:
+ _warn_multiple_option(option)
+ else:
+ value = arg[len(single_option_prefix):]
if remove:
sys.argv[index:index + 1] = []
- self.dict[name] = value
- return value
+ if value is None:
+ value = os.getenv(name.upper().replace('-', '_'))
- env_val = os.getenv(name.upper().replace('-', '_'))
- self.dict[name] = env_val
- return env_val
+ self.dict[name] = value
+ return value
options = Options()
diff --git a/missing_bindings.py b/missing_bindings.py
index ad7cfce52..dfd94912d 100644
--- a/missing_bindings.py
+++ b/missing_bindings.py
@@ -106,7 +106,7 @@ modules_to_test['QtX11Extras'] = 'qtx11extras-module.html'
modules_to_test['QtWinExtras'] = 'qtwinextras-module.html'
modules_to_test['QtXml'] = 'qtxml-module.html'
modules_to_test['QtXmlPatterns'] = 'qtxmlpatterns-module.html'
-modules_to_test['QtCharts'] = 'qt-charts-module.html'
+modules_to_test['QtCharts'] = 'qtcharts-module.html'
modules_to_test['QtDataVisualization'] = 'qtdatavisualization-module.html'
types_to_ignore = set()
@@ -216,7 +216,7 @@ qt_documentation_website_prefixes['5.6'] = 'http://doc.qt.io/qt-5.6/'
qt_documentation_website_prefixes['5.8'] = 'http://doc.qt.io/qt-5.8/'
qt_documentation_website_prefixes['5.9'] = 'http://doc.qt.io/qt-5.9/'
qt_documentation_website_prefixes['5.10'] = 'http://doc.qt.io/qt-5.10/'
-qt_documentation_website_prefixes['5.11'] = 'http://doc.qt.io/qt-5/'
+qt_documentation_website_prefixes['5.11'] = 'http://doc.qt.io/qt-5.11/'
qt_documentation_website_prefixes['dev'] = 'http://doc-snapshots.qt.io/qt5-dev/'
@@ -347,8 +347,12 @@ for module_name in modules_to_test.keys():
continue
try:
+ pyqt_module_name = module_name
+ if module_name == "QtCharts":
+ pyqt_module_name = module_name[:-1]
+
pyqt_tested_module = getattr(__import__(pyqt_package_name,
- fromlist=[module_name]), module_name)
+ fromlist=[pyqt_module_name]), pyqt_module_name)
except Exception as e:
log("\nCould not load {}.{} for comparison. "
"Received error: {}.\n".format(pyqt_package_name, module_name,
@@ -378,13 +382,13 @@ for module_name in modules_to_test.keys():
try:
pyside_qualified_type = 'pyside_tested_module.'
- if "Charts" in module_name:
+ if "QtCharts" == module_name:
pyside_qualified_type += 'QtCharts.'
elif "DataVisualization" in module_name:
pyside_qualified_type += 'QtDataVisualization.'
pyside_qualified_type += qt_type
- o = eval(pyside_qualified_type)
+ eval(pyside_qualified_type)
except:
missing_type = qt_type
missing_types_count += 1
diff --git a/sources/cmake_helpers/helpers.cmake b/sources/cmake_helpers/helpers.cmake
index dd2e98a3a..e64b8d9d3 100644
--- a/sources/cmake_helpers/helpers.cmake
+++ b/sources/cmake_helpers/helpers.cmake
@@ -61,3 +61,18 @@ macro(compute_config_py_values
endif()
endmacro()
+
+# Creates a new target called "${library_name}_generator" which
+# depends on the mjb_rejected_classes.log file generated by shiboken.
+# This target is added as a dependency to ${library_name} target.
+# This file's timestamp informs cmake when the last generation was
+# done, without force-updating the timestamps of the generated class
+# cpp files.
+# In practical terms this means that changing some injection code in
+# an xml file that modifies only one specific class cpp file, will
+# not force rebuilding all the cpp files, and thus allow for better
+# incremental builds.
+macro(create_generator_target library_name)
+ add_custom_target(${library_name}_generator DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log")
+ add_dependencies(${library_name} ${library_name}_generator)
+endmacro()
diff --git a/sources/pyside2/PySide2/Qt3DCore/typesystem_3dcore.xml b/sources/pyside2/PySide2/Qt3DCore/typesystem_3dcore.xml
index fb7a83ba7..013a49165 100644
--- a/sources/pyside2/PySide2/Qt3DCore/typesystem_3dcore.xml
+++ b/sources/pyside2/PySide2/Qt3DCore/typesystem_3dcore.xml
@@ -45,19 +45,41 @@
<namespace-type name="Qt3DCore">
<enum-type name="ChangeFlag" flags="ChangeFlags"/>
<object-type name="QAbstractAspect"/>
+ <object-type name="QAbstractEngine"/>
<object-type name="QAbstractSkeleton" since="5.10"/>
<object-type name="QArmature" since="5.10"/>
- <object-type name="QAspectEngine"/>
+ <object-type name="QAspectEngine">
+ <modify-function signature="registerAspect(Qt3DCore::QAbstractAspect*)">
+ <modify-argument index="this">
+ <parent index="1" action="add"/>
+ </modify-argument>
+ </modify-function>
+ </object-type>
<object-type name="QAspectJob"/>
<object-type name="QBackendNode">
<enum-type name="Mode"/>
</object-type>
+ <!-- TODO: Solve issues related to windows and a unresolved
+ external symbol
+ <object-type name="QBackendNodeMapper"/>-->
<object-type name="QComponent"/>
<object-type name="QComponentAddedChange"/>
<object-type name="QComponentRemovedChange"/>
<object-type name="QDynamicPropertyUpdatedChange"/>
- <object-type name="QEntity"/>
- <object-type name="QJoint" since="5.10"/>
+ <object-type name="QEntity">
+ <modify-function signature="addComponent(Qt3DCore::QComponent*)">
+ <modify-argument index="this">
+ <parent index="1" action="add"/>
+ </modify-argument>
+ </modify-function>
+ </object-type>
+ <object-type name="QJoint" since="5.10">
+ <modify-function signature="addChildJoint(Qt3DCore::QJoint*)">
+ <modify-argument index="this">
+ <parent index="1" action="add"/>
+ </modify-argument>
+ </modify-function>
+ </object-type>
<object-type name="QNode">
<enum-type name="PropertyTrackingMode"/>
</object-type>
@@ -88,5 +110,10 @@
<!-- Disambiguate from QtGui/qtransform.h -->
<include file-name="Qt3DCore/qtransform.h" location="global"/>
</object-type>
+ <namespace-type name="Quick">
+ <object-type name="QQmlAspectEngine">
+ <enum-type name="Status"/>
+ </object-type>
+ </namespace-type>
</namespace-type>
</typesystem>
diff --git a/sources/pyside2/PySide2/Qt3DInput/typesystem_3dinput.xml b/sources/pyside2/PySide2/Qt3DInput/typesystem_3dinput.xml
index f2b408257..ebac94f03 100644
--- a/sources/pyside2/PySide2/Qt3DInput/typesystem_3dinput.xml
+++ b/sources/pyside2/PySide2/Qt3DInput/typesystem_3dinput.xml
@@ -45,7 +45,9 @@
<namespace-type name="Qt3DInput">
<object-type name="QAbstractActionInput"/>
<object-type name="QAbstractAxisInput"/>
- <object-type name="QAbstractPhysicalDevice"/>
+ <object-type name="QAbstractPhysicalDevice">
+ <enum-type name="DeviceStatus"/>
+ </object-type>
<object-type name="QAction"/>
<object-type name="QActionInput"/>
<object-type name="QAnalogAxisInput"/>
@@ -57,12 +59,17 @@
<object-type name="QButtonAxisInput"/>
<object-type name="QInputAspect"/>
<object-type name="QInputChord"/>
+ <!-- On windows this raises the following error:
+ type 'Qt3DInput::QInputDeviceIntegration' is specified in typesystem, but not defined.
+ This could potentially lead to compilation errors.
+ <object-type name="QInputDeviceIntegration"/>
+ -->
<object-type name="QInputSequence"/>
<object-type name="QInputSettings"/>
+ <object-type name="QKeyboardDevice"/>
<object-type name="QKeyboardHandler"/>
<object-type name="QKeyEvent"/>
<object-type name="QLogicalDevice"/>
- <object-type name="QKeyboardDevice"/>
<object-type name="QMouseDevice">
<enum-type name="Axis"/>
</object-type>
@@ -75,5 +82,11 @@
<enum-type name="Modifiers"/>
</object-type>
<object-type name="QMouseHandler"/>
+ <!-- On windows this raise the following error:
+ qt3dinput_module_wrapper.cpp.obj : error LNK2019:
+ unresolved external symbol "void __cdecl init_Qt3DInput_QPhysicalDeviceCreatedChangeBase(struct _object *)"
+ (?init_Qt3DInput_QPhysicalDeviceCreatedChangeBase@@YAXPAU_object@@@Z) referenced in function _PyInit_Qt3DInput
+ <object-type name="QPhysicalDeviceCreatedChangeBase"/>
+ -->
</namespace-type>
</typesystem>
diff --git a/sources/pyside2/PySide2/QtCore/CMakeLists.txt b/sources/pyside2/PySide2/QtCore/CMakeLists.txt
index 466e97756..e583bd0f4 100644
--- a/sources/pyside2/PySide2/QtCore/CMakeLists.txt
+++ b/sources/pyside2/PySide2/QtCore/CMakeLists.txt
@@ -16,6 +16,7 @@ ${QtCore_GEN_DIR}/qabstracteventdispatcher_timerinfo_wrapper.cpp
${QtCore_GEN_DIR}/qabstracteventdispatcher_wrapper.cpp
${QtCore_GEN_DIR}/qabstractitemmodel_wrapper.cpp
${QtCore_GEN_DIR}/qabstractlistmodel_wrapper.cpp
+${QtCore_GEN_DIR}/qabstractnativeeventfilter_wrapper.cpp
${QtCore_GEN_DIR}/qabstractproxymodel_wrapper.cpp
${QtCore_GEN_DIR}/qabstractstate_wrapper.cpp
${QtCore_GEN_DIR}/qabstracttablemodel_wrapper.cpp
diff --git a/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml b/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml
index 838d95896..005fd0684 100644
--- a/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml
+++ b/sources/pyside2/PySide2/QtCore/typesystem_core_common.xml
@@ -74,6 +74,10 @@
<function signature="qVersion()" />
<function signature="qrand()" />
<function signature="qsrand(uint)" />
+ <function signature="qCompress(const uchar*,int,int)"/>
+ <function signature="qCompress(const QByteArray&amp;,int)"/>
+ <function signature="qUncompress(const uchar*,int)"/>
+ <function signature="qUncompress(const QByteArray&amp;)"/>
<inject-code class="native" position="beginning">
#include &lt;pyside.h&gt;
@@ -938,9 +942,6 @@
<rejection class="" enum-name="QtValidLicenseForGuiModule"/>
<rejection class="" enum-name="QtValidLicenseForScriptModule"/>
<rejection class="" enum-name="QtValidLicenseForHelpModule"/>
- <rejection class="QAbstractEventDispatcher" function-name="filterEvent"/>
- <rejection class="QAbstractEventDispatcher" function-name="filterNativeEvent"/>
- <rejection class="QAbstractEventDispatcher" function-name="setEventFilter"/>
<!-- Internal -->
<rejection class="QAbstractFileEngine"/> <!--
<rejection class="QAbstractFileEngine" function-name="endEntryList"/>
@@ -2978,6 +2979,26 @@
<object-type name="QXmlStreamEntityResolver"/>
<!-- Qt5: had to move QAbstractEventDispatcher into os-specific files because of Windows -->
+ <object-type name="QAbstractNativeEventFilter">
+ <!-- see QWidget::nativeEvent(), QWindow::nativeEvent() -->
+ <modify-function signature="nativeEventFilter(const QByteArray&amp;,void*,long*)">
+ <modify-argument index="3">
+ <remove-argument/>
+ <conversion-rule class="native">
+ <insert-template name="return_native_eventfilter_conversion_variables"/>
+ </conversion-rule>
+ </modify-argument>
+ <modify-argument index="return">
+ <replace-type modified-type="PyObject"/>
+ <conversion-rule class="native">
+ <insert-template name="return_native_eventfilter_conversion"/>
+ </conversion-rule>
+ </modify-argument>
+ <inject-code position="end">
+ <insert-template name="return_native_eventfilter"/>
+ </inject-code>
+ </modify-function>
+ </object-type>
<object-type name="QEventLoop">
<enum-type name="ProcessEventsFlag" flags="ProcessEventsFlags"/>
diff --git a/sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml b/sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml
index 32d586631..e2e3b2335 100644
--- a/sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml
+++ b/sources/pyside2/PySide2/QtGui/typesystem_gui_common.xml
@@ -2987,11 +2987,26 @@
<enum-type name="AncestorMode"/>
<enum-type name="Visibility"/>
<modify-function signature="raise()" rename="raise_" />
+ <!-- see QWidget::nativeEvent(), QAbstractNativeEventFilter::nativeEventFilter() -->
+ <modify-function signature="nativeEvent(const QByteArray &amp;,void*,long*)">
+ <modify-argument index="3">
+ <remove-argument/>
+ <conversion-rule class="native">
+ <insert-template name="return_native_eventfilter_conversion_variables"/>
+ </conversion-rule>
+ </modify-argument>
+ <modify-argument index="return">
+ <replace-type modified-type="PyObject"/>
+ <conversion-rule class="native">
+ <insert-template name="return_native_eventfilter_conversion"/>
+ </conversion-rule>
+ </modify-argument>
+ <inject-code position="end">
+ <insert-template name="return_native_eventfilter"/>
+ </inject-code>
+ </modify-function>
</object-type>
- <!-- Qt5: not sure if this needs support, skipped for now -->
- <rejection class="QWindow" function-name="nativeEvent"/>"
-
<object-type name="QGuiApplication">
<extra-includes>
<include file-name="QBasicTimer" location="global"/>
diff --git a/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp b/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp
index 4e45cfdcc..9d9ddc799 100644
--- a/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp
+++ b/sources/pyside2/PySide2/QtQml/pysideqmlregistertype.cpp
@@ -172,13 +172,13 @@ int PySide::qmlRegisterType(PyObject *pyObj, const char *uri, int versionMajor,
type.versionMajor = versionMajor;
type.versionMinor = versionMinor;
type.elementName = qmlName;
- type.metaObject = metaObject;
type.extensionObjectCreate = 0;
type.extensionMetaObject = 0;
type.customParser = 0;
++nextType;
}
+ type.metaObject = metaObject; // Snapshot may have changed.
int qmlTypeId = QQmlPrivate::qmlregister(QQmlPrivate::TypeRegistration, &type);
if (qmlTypeId == -1) {
@@ -235,7 +235,7 @@ void propListTpFree(void* self)
static PyType_Slot PropertyListType_slots[] = {
{Py_tp_init, (void *)propListTpInit},
{Py_tp_free, (void *)propListTpFree},
- {Py_tp_dealloc, (void *)SbkDummyDealloc},
+ {Py_tp_dealloc, (void *)object_dealloc},
{0, 0}
};
static PyType_Spec PropertyListType_spec = {
@@ -449,7 +449,7 @@ static PyType_Slot QtQml_VolatileBoolType_slots[] = {
{Py_tp_str, (void *)reinterpret_cast<reprfunc>(QtQml_VolatileBoolObject_str)},
{Py_tp_methods, (void *)QtQml_VolatileBoolObject_methods},
{Py_tp_new, (void *)QtQml_VolatileBoolObject_new},
- {Py_tp_dealloc, (void *)SbkDummyDealloc},
+ {Py_tp_dealloc, (void *)object_dealloc},
{0, 0}
};
static PyType_Spec QtQml_VolatileBoolType_spec = {
diff --git a/sources/pyside2/PySide2/QtWidgets/typesystem_widgets_common.xml b/sources/pyside2/PySide2/QtWidgets/typesystem_widgets_common.xml
index 1f2cd446b..d92540d85 100644
--- a/sources/pyside2/PySide2/QtWidgets/typesystem_widgets_common.xml
+++ b/sources/pyside2/PySide2/QtWidgets/typesystem_widgets_common.xml
@@ -2197,8 +2197,24 @@
</object-type>
<object-type name="QWidget" delete-in-main-thread="true">
- <!-- Qt5: remove native event for now -->
- <modify-function signature="nativeEvent(const QByteArray &amp;,void*,long*)" remove="all" />
+ <!-- see QWindow::nativeEvent(), QAbstractNativeEventFilter::nativeEventFilter() -->
+ <modify-function signature="nativeEvent(const QByteArray &amp;,void*,long*)">
+ <modify-argument index="3">
+ <remove-argument/>
+ <conversion-rule class="native">
+ <insert-template name="return_native_eventfilter_conversion_variables"/>
+ </conversion-rule>
+ </modify-argument>
+ <modify-argument index="return">
+ <replace-type modified-type="PyObject"/>
+ <conversion-rule class="native">
+ <insert-template name="return_native_eventfilter_conversion"/>
+ </conversion-rule>
+ </modify-argument>
+ <inject-code position="end">
+ <insert-template name="return_native_eventfilter"/>
+ </inject-code>
+ </modify-function>
<extra-includes>
<include file-name="QIcon" location="global"/>
diff --git a/sources/pyside2/PySide2/typesystem_templates.xml b/sources/pyside2/PySide2/typesystem_templates.xml
index 1a140906b..a7a7bfc9d 100644
--- a/sources/pyside2/PySide2/typesystem_templates.xml
+++ b/sources/pyside2/PySide2/typesystem_templates.xml
@@ -361,6 +361,26 @@
Py_INCREF(%PYARG_0);
</template>
+ <!-- Helpers for modifying "bool nativeEventFilter(QByteArray, void*, long *result)"
+ to return a tuple of bool,long -->
+ <template name="return_native_eventfilter_conversion_variables">
+ long resultVar{0};
+ long *%out = &amp;resultVar;
+ </template>
+ <template name="return_native_eventfilter_conversion">
+ %RETURN_TYPE %out = false;
+ if (PySequence_Check(%PYARG_0) &amp;&amp; (PySequence_Size(%PYARG_0) == 2)) {
+ Shiboken::AutoDecRef pyItem(PySequence_GetItem(%PYARG_0, 0));
+ %out = %CONVERTTOCPP[bool](pyItem);
+ }
+ </template>
+
+ <template name="return_native_eventfilter">
+ %PYARG_0 = PyTuple_New(2);
+ PyTuple_SET_ITEM(%PYARG_0, 0, %CONVERTTOPYTHON[%RETURN_TYPE](%0));
+ PyTuple_SET_ITEM(%PYARG_0, 1, %CONVERTTOPYTHON[long](*result_out));
+ </template>
+
<!-- templates for __reduce__ -->
<template name="reduce_code">
%PYARG_0 = Py_BuildValue("(N(%REDUCE_FORMAT))", PyObject_Type(%PYSELF), %REDUCE_ARGS);
diff --git a/sources/pyside2/cmake/Macros/PySideModules.cmake b/sources/pyside2/cmake/Macros/PySideModules.cmake
index 816190612..0f8b500ac 100644
--- a/sources/pyside2/cmake/Macros/PySideModules.cmake
+++ b/sources/pyside2/cmake/Macros/PySideModules.cmake
@@ -80,7 +80,8 @@ macro(create_pyside_module
get_filename_component(pyside_binary_dir ${CMAKE_CURRENT_BINARY_DIR} DIRECTORY)
- add_custom_command(OUTPUT ${${module_sources}}
+ add_custom_command( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log"
+ BYPRODUCTS ${${module_sources}}
COMMAND "${SHIBOKEN_BINARY}" ${GENERATOR_EXTRA_FLAGS}
"${pyside2_BINARY_DIR}/${module_name}_global.h"
--include-paths=${shiboken_include_dirs}
@@ -112,6 +113,7 @@ macro(create_pyside_module
if(${module_deps})
add_dependencies(${module_name} ${${module_deps}})
endif()
+ create_generator_target(${module_name})
# install
install(TARGETS ${module_name} LIBRARY DESTINATION ${PYTHON_SITE_PACKAGES}/PySide2)
diff --git a/sources/pyside2/libpyside/CMakeLists.txt b/sources/pyside2/libpyside/CMakeLists.txt
index 101b32e4a..ec6713b62 100644
--- a/sources/pyside2/libpyside/CMakeLists.txt
+++ b/sources/pyside2/libpyside/CMakeLists.txt
@@ -82,7 +82,8 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}
${SHIBOKEN_INCLUDE_DIR}
${SHIBOKEN_PYTHON_INCLUDE_DIR}
${QML_INCLUDES}
- ${Qt5Core_INCLUDE_DIRS})
+ ${Qt5Core_INCLUDE_DIRS}
+ ${Qt5Core_PRIVATE_INCLUDE_DIRS})
add_library(pyside2 SHARED ${libpyside_SRC} ${other_files})
target_link_libraries(pyside2
${SHIBOKEN_PYTHON_LIBRARIES}
diff --git a/sources/pyside2/libpyside/dynamicqmetaobject.cpp b/sources/pyside2/libpyside/dynamicqmetaobject.cpp
index 525e24f4a..5cbfa70f9 100644
--- a/sources/pyside2/libpyside/dynamicqmetaobject.cpp
+++ b/sources/pyside2/libpyside/dynamicqmetaobject.cpp
@@ -50,521 +50,371 @@
#include <QtCore/QByteArray>
#include <QtCore/QObject>
#include <QtCore/QStringList>
+#include <QtCore/QTextStream>
#include <QtCore/QVector>
+#include <private/qmetaobjectbuilder_p.h>
#include <cstring>
-
-#define EMPTY_META_METHOD "0()"
+#include <vector>
using namespace PySide;
-enum PropertyFlags {
- Invalid = 0x00000000,
- Readable = 0x00000001,
- Writable = 0x00000002,
- Resettable = 0x00000004,
- EnumOrFlag = 0x00000008,
- StdCppSet = 0x00000100,
-// Override = 0x00000200,
- Constant = 0x00000400,
- Final = 0x00000800,
- Designable = 0x00001000,
- ResolveDesignable = 0x00002000,
- Scriptable = 0x00004000,
- ResolveScriptable = 0x00008000,
- Stored = 0x00010000,
- ResolveStored = 0x00020000,
- Editable = 0x00040000,
- ResolveEditable = 0x00080000,
- User = 0x00100000,
- ResolveUser = 0x00200000,
- Notify = 0x00400000
-};
-
-// these values are from moc source code, generator.cpp:66
-enum MethodFlags {
- AccessPrivate = 0x00,
- AccessProtected = 0x01,
- AccessPublic = 0x02,
- MethodMethod = 0x00,
- MethodSignal = 0x04,
- MethodSlot = 0x08,
- MethodConstructor = 0x0c,
- MethodCompatibility = 0x10,
- MethodCloned = 0x20,
- MethodScriptable = 0x40
-};
-
-enum MetaDataFlags {
- IsUnresolvedType = 0x80000000,
- TypeNameIndexMask = 0x7FFFFFFF
-};
-
-class DynamicQMetaObject::DynamicQMetaObjectPrivate
+// MetaObjectBuilder: Provides the QMetaObject's returned by
+// QObject::metaObject() for PySide2 objects. There are several
+// scenarios to consider:
+// 1) A plain Qt class (say QTimer) is instantiated. In that case,
+// return the base meta object until a modification is made by
+// adding methods, properties or class info (cf qmetaobject_test.py).
+// In that case, instantiate a QMetaObjectBuilder inheriting the
+// base meta meta object, add the method and return the result
+// of QMetaObjectBuilder::toMetaObject() (with dirty handling should
+// further modifications be made).
+// 2) A Python class inheriting a Qt class is instantiated. For this,
+// instantiate a QMetaObjectBuilder and add the methods/properties
+// found by inspecting the Python class.
+
+class MetaObjectBuilderPrivate
{
public:
- QList<MethodData> m_methods;
- QList<PropertyData> m_properties;
-
- QMap<QByteArray, QByteArray> m_info;
- QByteArray m_className;
-
- bool m_updated = false; // when the meta data is not update
- int m_methodOffset = 0;
- int m_propertyOffset = 0;
- int m_dataSize = 0;
- int m_emptyMethod = -1;
- int m_nullIndex = 0;
-
- int createMetaData(QMetaObject* metaObj);
- void updateMetaObject(QMetaObject* metaObj);
- void writeMethodsData(const QList<MethodData>& methods, unsigned int** data,
- QByteArrayList& strings, int* prtIndex,
- int nullIndex, int flags);
- void writeStringData(char *, const QByteArrayList& strings) const;
+ using MetaObjects = std::vector<const QMetaObject *>;
+
+ QMetaObjectBuilder *ensureBuilder();
+ void parsePythonType(PyTypeObject *type);
+ int indexOfMethod(QMetaMethod::MethodType mtype,
+ const QByteArray &signature) const;
+ int indexOfProperty(const QByteArray &name) const;
+ int addSlot(const QByteArray &signature);
+ int addSlot(const QByteArray &signature, const QByteArray &type);
+ int addSignal(const QByteArray &signature);
+ void removeMethod(QMetaMethod::MethodType mtype, int index);
int getPropertyNotifyId(PySideProperty *property) const;
-};
+ int addProperty(const QByteArray &property, PyObject *data);
+ void addInfo(const QByteArray &key, const QByteArray &value);
+ void addInfo(const QMap<QByteArray, QByteArray> &info);
+ void removeProperty(int index);
+ const QMetaObject *update();
-bool sortMethodSignalSlot(const MethodData &m1, const MethodData &m2)
-{
- if (m1.methodType() == QMetaMethod::Signal)
- return m2.methodType() == QMetaMethod::Slot;
- return false;
-}
+ QMetaObjectBuilder *m_builder = nullptr;
-static int registerString(const QByteArray& s, QByteArrayList& strings)
-{
- int idx = strings.indexOf(s);
- if (idx == -1) {
- idx = strings.size();
- strings.append(s);
- }
- return idx;
-}
-
-static int blobSize(const QByteArrayList &strings)
-{
- int size = strings.size() * int(sizeof(QByteArrayData));
- for (const QByteArray &field : strings)
- size += field.size() + 1;
- return size;
-}
-
-static int aggregateParameterCount(const QList<MethodData> &methods)
-{
- int sum = 0;
- for (const auto &method : methods)
- sum += method.parameterCount() * 2 + 1; // nb_param*2 (type and names) +1 for return type
- return sum;
-}
+ const QMetaObject *m_baseObject = nullptr;
+ MetaObjects m_cachedMetaObjects;
+ bool m_dirty = true;
+};
-static void writeString(char *out, int i, const QByteArray &str,
- const int offsetOfStringdataMember, int &stringdataOffset)
+QMetaObjectBuilder *MetaObjectBuilderPrivate::ensureBuilder()
{
- int size = str.size();
- qptrdiff offset = offsetOfStringdataMember + stringdataOffset
- - i * sizeof(QByteArrayData);
- const QByteArrayData data =
- Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, offset);
-
- memcpy(out + i * sizeof(QByteArrayData), &data, sizeof(QByteArrayData));
-
- memcpy(out + offsetOfStringdataMember + stringdataOffset, str.constData(), size);
- out[offsetOfStringdataMember + stringdataOffset + size] = '\0';
-
- stringdataOffset += size + 1;
+ if (!m_builder) {
+ m_builder = new QMetaObjectBuilder();
+ m_builder->setClassName(m_baseObject->className());
+ m_builder->setSuperClass(m_baseObject);
+ }
+ return m_builder;
}
-static int qvariant_nameToType(const char* name)
+MetaObjectBuilder::MetaObjectBuilder(const char *className, const QMetaObject *metaObject) :
+ m_d(new MetaObjectBuilderPrivate)
{
- if (!name)
- return 0;
-
- if (strcmp(name, "QVariant") == 0)
- return 0xffffffff;
- if (strcmp(name, "QCString") == 0)
- return QMetaType::QByteArray;
- if (strcmp(name, "Q_LLONG") == 0)
- return QMetaType::LongLong;
- if (strcmp(name, "Q_ULLONG") == 0)
- return QMetaType::ULongLong;
- if (strcmp(name, "QIconSet") == 0)
- return QMetaType::QIcon;
-
- uint tp = QMetaType::type(name);
- return tp < QMetaType::User ? tp : 0;
+ m_d->m_baseObject = metaObject;
+ m_d->m_builder = new QMetaObjectBuilder();
+ m_d->m_builder->setClassName(className);
+ m_d->m_builder->setSuperClass(metaObject);
+ m_d->m_builder->setClassName(className);
}
-/*
- Returns true if the type is a QVariant types.
-*/
-static bool isVariantType(const char* type)
+MetaObjectBuilder::MetaObjectBuilder(PyTypeObject *type, const QMetaObject *metaObject)
+ : m_d(new MetaObjectBuilderPrivate)
{
- return qvariant_nameToType(type) != 0;
+ m_d->m_baseObject = metaObject;
+ const char *className = type->tp_name;
+ if (const char *lastDot = strrchr(type->tp_name, '.'))
+ className = lastDot + 1;
+ // Different names indicate a Python class inheriting a Qt class.
+ // Parse the type.
+ if (strcmp(className, metaObject->className()) != 0) {
+ m_d->m_builder = new QMetaObjectBuilder();
+ m_d->m_builder->setClassName(className);
+ m_d->m_builder->setSuperClass(metaObject);
+ m_d->parsePythonType(type);
+ }
}
-/*!
- Returns true if the type is qreal.
-*/
-static bool isQRealType(const char *type)
+MetaObjectBuilder::~MetaObjectBuilder()
{
- return strcmp(type, "qreal") == 0;
+ qDeleteAll(m_d->m_cachedMetaObjects);
+ delete m_d->m_builder;
+ delete m_d;
}
-uint PropertyData::flags() const
+int MetaObjectBuilderPrivate::indexOfMethod(QMetaMethod::MethodType mtype,
+ const QByteArray &signature) const
{
- const QByteArray btype(type());
- const char* typeName = btype.data();
- uint flags = Invalid;
- if (!isVariantType(typeName))
- flags |= EnumOrFlag;
- else if (!isQRealType(typeName))
- flags |= qvariant_nameToType(typeName) << 24;
-
- if (PySide::Property::isReadable(m_data))
- flags |= Readable;
-
- if (PySide::Property::isWritable(m_data))
- flags |= Writable;
-
- if (PySide::Property::hasReset(m_data))
- flags |= Resettable;
-
- if (PySide::Property::isDesignable(m_data))
- flags |= Designable;
- else
- flags |= ResolveDesignable;
-
- if (PySide::Property::isScriptable(m_data))
- flags |= Scriptable;
- else
- flags |= ResolveScriptable;
-
- if (PySide::Property::isStored(m_data))
- flags |= Stored;
- else
- flags |= ResolveStored;
-
- //EDITABLE
- flags |= ResolveEditable;
-
- if (PySide::Property::isUser(m_data))
- flags |= User;
- else
- flags |= ResolveUser;
-
- if (m_cachedNotifyId != -1)
- flags |= Notify;
-
- if (PySide::Property::isConstant(m_data))
- flags |= Constant;
-
- if (PySide::Property::isFinal(m_data))
- flags |= Final;
-
- return flags;
+ int result = -1;
+ if (m_builder) {
+ switch (mtype) {
+ case QMetaMethod::Signal:
+ result = m_builder->indexOfSignal(signature);
+ break;
+ case QMetaMethod::Slot:
+ result = m_builder->indexOfSlot(signature);
+ break;
+ case QMetaMethod::Constructor:
+ result = m_builder->indexOfConstructor(signature);
+ break;
+ case QMetaMethod::Method:
+ result = m_builder->indexOfMethod(signature);
+ break;
+ }
+ if (result >= 0)
+ return result + m_baseObject->methodCount();
+ }
+ switch (mtype) {
+ case QMetaMethod::Signal:
+ result = m_baseObject->indexOfSignal(signature);
+ break;
+ case QMetaMethod::Slot:
+ result = m_baseObject->indexOfSlot(signature);
+ break;
+ case QMetaMethod::Constructor:
+ result = m_baseObject->indexOfConstructor(signature);
+ break;
+ case QMetaMethod::Method:
+ result = m_baseObject->indexOfMethod(signature);
+ break;
+ }
+ return result;
}
-// const QByteArray with EMPTY_META_METHOD, used to save some memory
-const QByteArray MethodData::m_emptySig(EMPTY_META_METHOD);
-
-MethodData::MethodData()
- : m_signature(m_emptySig)
+int MetaObjectBuilder::indexOfMethod(QMetaMethod::MethodType mtype,
+ const QByteArray &signature) const
{
+ return m_d->indexOfMethod(mtype, signature);
}
-MethodData::MethodData(QMetaMethod::MethodType mtype, const QByteArray& signature, const QByteArray& rtype)
- : m_signature(QMetaObject::normalizedSignature(signature.constData()))
- , m_rtype(QMetaObject::normalizedSignature(rtype.constData()))
- , m_mtype(mtype)
+int MetaObjectBuilderPrivate::indexOfProperty(const QByteArray &name) const
{
+ if (m_builder) {
+ const int result = m_builder->indexOfProperty(name);
+ if (result >= 0)
+ return m_baseObject->propertyCount() + result;
+ }
+ return m_baseObject->indexOfProperty(name);
}
-void MethodData::clear()
+int MetaObjectBuilder::indexOfProperty(const QByteArray &name) const
{
- m_signature = m_emptySig;
- m_rtype.clear();
+ return m_d->indexOfProperty(name);
}
-bool MethodData::isValid() const
+static bool checkMethodSignature(const QByteArray &signature)
{
- return m_signature != m_emptySig;
-}
-
-QList<QByteArray> MethodData::parameterTypes() const
-{
- const char *signature = m_signature.constData();
- QList<QByteArray> list;
- while (*signature && *signature != '(')
- ++signature;
- while (*signature && *signature != ')' && *++signature != ')') {
- const char *begin = signature;
- int level = 0;
- while (*signature && (level > 0 || *signature != ',') && *signature != ')') {
- if (*signature == '<')
- ++level;
- else if (*signature == '>')
- --level;
- ++signature;
- }
- list += QByteArray(begin, signature - begin);
- }
- return list;
+ // Common mistake not to add parentheses to the signature.
+ const int openParen = signature.indexOf('(');
+ const int closingParen = signature.lastIndexOf(')');
+ const bool ok = openParen != -1 && closingParen != -1 && openParen < closingParen;
+ if (!ok) {
+ const QByteArray message =
+ "MetaObjectBuilder::addMethod: Invalid method signature provided for \""
+ + signature + '"';
+ PyErr_WarnEx(PyExc_RuntimeWarning, message.constData(), 0);
+ }
+ return ok;
}
-int MethodData::parameterCount() const
+int MetaObjectBuilderPrivate::addSlot(const QByteArray &signature)
{
- return parameterTypes().size();
+ if (!checkMethodSignature(signature))
+ return -1;
+ m_dirty = true;
+ return m_baseObject->methodCount()
+ + ensureBuilder()->addSlot(signature).index();
}
-QByteArray MethodData::name() const
+int MetaObjectBuilder::addSlot(const char *signature)
{
- return m_signature.left(qMax(m_signature.indexOf('('), 0));
+ return m_d->addSlot(signature);
}
-PropertyData::PropertyData()
- : m_cachedNotifyId(0), m_data(0)
+int MetaObjectBuilderPrivate::addSlot(const QByteArray &signature,
+ const QByteArray &type)
{
+ if (!checkMethodSignature(signature))
+ return -1;
+ m_dirty = true;
+ QMetaMethodBuilder methodBuilder = ensureBuilder()->addSlot(signature);
+ methodBuilder.setReturnType(type);
+ return m_baseObject->methodCount() + methodBuilder.index();
}
-PropertyData::PropertyData(const char* name, int notifyId, PySideProperty* data)
- : m_name(name), m_cachedNotifyId(notifyId), m_data(data)
+int MetaObjectBuilder::addSlot(const char *signature, const char *type)
{
+ return m_d->addSlot(signature, type);
}
-QByteArray PropertyData::type() const
+int MetaObjectBuilderPrivate::addSignal(const QByteArray &signature)
{
- return QByteArray(PySide::Property::getTypeName(m_data));
+ if (!checkMethodSignature(signature))
+ return -1;
+ m_dirty = true;
+ return m_baseObject->methodCount()
+ + ensureBuilder()->addSignal(signature).index();
}
-
-bool PropertyData::isValid() const
+int MetaObjectBuilder::addSignal(const char *signature)
{
- return !m_name.isEmpty();
+ return m_d->addSignal(signature);
}
-int PropertyData::cachedNotifyId() const
+void MetaObjectBuilderPrivate::removeMethod(QMetaMethod::MethodType mtype,
+ int index)
{
- return m_cachedNotifyId;
+ index -= m_baseObject->methodCount();
+ auto builder = ensureBuilder();
+ Q_ASSERT(index >= 0 && index < builder->methodCount());
+ switch (mtype) {
+ case QMetaMethod::Constructor:
+ builder->removeConstructor(index);
+ break;
+ default:
+ builder->removeMethod(index);
+ break;
+ }
+ m_dirty = true;
}
-bool PropertyData::operator==(const PropertyData& other) const
+void MetaObjectBuilder::removeMethod(QMetaMethod::MethodType mtype, int index)
{
- return m_data == other.m_data;
+ m_d->removeMethod(mtype, index);
}
-bool PropertyData::operator==(const char* name) const
+int MetaObjectBuilderPrivate::getPropertyNotifyId(PySideProperty *property) const
{
- return m_name == name;
+ int notifyId = -1;
+ if (property->d->notify) {
+ if (const char *signalNotify = PySide::Property::getNotifyName(property))
+ notifyId = indexOfMethod(QMetaMethod::Signal, signalNotify);
+ }
+ return notifyId;
}
-
-DynamicQMetaObject::DynamicQMetaObject(PyTypeObject* type, const QMetaObject* base)
- : m_d(new DynamicQMetaObjectPrivate)
+int MetaObjectBuilderPrivate::addProperty(const QByteArray &propertyName,
+ PyObject *data)
{
- d.superdata = base;
- d.stringdata = NULL;
- d.data = NULL;
- d.extradata = NULL;
- d.relatedMetaObjects = NULL;
- d.static_metacall = NULL;
+ int index = indexOfProperty(propertyName);
+ if (index != -1)
+ return index;
- m_d->m_className = QByteArray(type->tp_name).split('.').last();
- m_d->m_methodOffset = base->methodCount() - 1;
- m_d->m_propertyOffset = base->propertyCount() - 1;
- parsePythonType(type);
+ PySideProperty *property = reinterpret_cast<PySideProperty *>(data);
+ int propertyNotifyId = getPropertyNotifyId(property);
+ if (propertyNotifyId >= 0)
+ propertyNotifyId -= m_baseObject->methodCount();
+ auto newProperty =
+ ensureBuilder()->addProperty(propertyName, property->d->typeName,
+ propertyNotifyId);
+ index = newProperty.index() + m_baseObject->propertyCount();
+ m_dirty = true;
+ return index;
}
-DynamicQMetaObject::DynamicQMetaObject(const char* className, const QMetaObject* metaObject)
- : m_d(new DynamicQMetaObjectPrivate)
+int MetaObjectBuilder::addProperty(const char *property, PyObject *data)
{
- d.superdata = metaObject;
- d.stringdata = 0;
- d.data = 0;
- d.extradata = 0;
- d.relatedMetaObjects = NULL;
- d.static_metacall = NULL;
-
- m_d->m_className = className;
- m_d->m_methodOffset = metaObject->methodCount() - 1;
- m_d->m_propertyOffset = metaObject->propertyCount() - 1;
+ return m_d->addProperty(property, data);
}
-DynamicQMetaObject::~DynamicQMetaObject()
+void MetaObjectBuilderPrivate::addInfo(const QByteArray &key,
+ const QByteArray &value)
{
- free(reinterpret_cast<char *>(const_cast<QByteArrayData *>(d.stringdata)));
- free(const_cast<uint*>(d.data));
- delete m_d;
+ ensureBuilder()->addClassInfo(key, value);
+ m_dirty = true;
}
-int DynamicQMetaObject::addMethod(QMetaMethod::MethodType mtype, const char* signature, const char* type)
+void MetaObjectBuilder::addInfo(const char *key, const char *value)
{
- int index = -1;
- int counter = 0;
-
- QList<MethodData>::iterator it = m_d->m_methods.begin();
- for (; it != m_d->m_methods.end(); ++it) {
- if ((it->signature() == signature) && (it->methodType() == mtype))
- return m_d->m_methodOffset + counter;
- if (!it->isValid())
- index = counter;
- counter++;
- }
-
- // Common mistake not to add parentheses to the signature.
- if ((strchr(signature, ')') == 0) || ((strchr(signature, '(') == 0))) {
- const QString message =
- QLatin1String("DynamicQMetaObject::addMethod: Invalid method signature "
- "provided for ") + QLatin1String(signature);
- const QByteArray messageLatin = message.toLatin1();
- PyErr_WarnEx(PyExc_RuntimeWarning, messageLatin.constData(), 0);
- return -1;
- }
-
- //has blank method
- if (index != -1) {
- m_d->m_methods[index] = MethodData(mtype, signature, type);
- index++;
- } else {
- m_d->m_methods << MethodData(mtype, signature, type);
- index = m_d->m_methods.size();
- }
-
- m_d->m_updated = false;
- return m_d->m_methodOffset + index;
+ m_d->addInfo(key, value);
}
-void DynamicQMetaObject::removeMethod(QMetaMethod::MethodType mtype, uint index)
+void MetaObjectBuilderPrivate::addInfo(const QMap<QByteArray, QByteArray> &info)
{
- const char* methodSig = method(index).methodSignature();
- QList<MethodData>::iterator it = m_d->m_methods.begin();
- for (; it != m_d->m_methods.end(); ++it) {
- if ((it->signature() == methodSig) && (it->methodType() == mtype)){
- it->clear();
- m_d->m_updated = false;
- break;
- }
- }
+ auto builder = ensureBuilder();
+ for (auto i = info.constBegin(), end = info.constEnd(); i != end; ++i)
+ builder->addClassInfo(i.key(), i.value());
+ m_dirty = true;
}
-int DynamicQMetaObject::addSignal(const char* signal, const char* type)
+void MetaObjectBuilder::addInfo(const QMap<QByteArray, QByteArray> &info)
{
- return addMethod(QMetaMethod::Signal, signal, type);
+ m_d->addInfo(info);
}
-int DynamicQMetaObject::addSlot(const char* slot, const char* type)
+void MetaObjectBuilderPrivate::removeProperty(int index)
{
- return addMethod(QMetaMethod::Slot, slot, type);
+ index -= m_baseObject->propertyCount();
+ auto builder = ensureBuilder();
+ Q_ASSERT(index >= 0 && index < builder->propertyCount());
+ builder->removeProperty(index);
+ m_dirty = true;
}
-void DynamicQMetaObject::removeSlot(uint index)
+void MetaObjectBuilder::removeProperty(int index)
{
- removeMethod(QMetaMethod::Slot, index);
+ m_d->removeProperty(index);
}
-void DynamicQMetaObject::removeSignal(uint index)
-{
- removeMethod(QMetaMethod::Signal, index);
-}
+// PYSIDE-315: Instead of sorting the items and maybe breaking indices, we
+// ensure that the signals and slots are sorted by the improved
+// parsePythonType() (signals must go before slots). The order can only
+// become distorted if the class is modified after creation. In that
+// case, we give a warning.
-int DynamicQMetaObject::addProperty(const char* propertyName, PyObject* data)
+static QString msgMethodSortOrder(const QMetaObject *mo, int offendingIndex)
{
- int index = m_d->m_properties.indexOf(propertyName);
- if (index != -1)
- return m_d->m_propertyOffset + index;
-
- // retrieve notifyId
- PySideProperty *property = reinterpret_cast<PySideProperty *>(data);
- const int notifyId = m_d->getPropertyNotifyId(property);
-
- //search for a empty space
- PropertyData blank;
- index = m_d->m_properties.indexOf(blank);
- if (index != -1) {
- m_d->m_properties[index] = PropertyData(propertyName, notifyId, property);
- } else {
- m_d->m_properties << PropertyData(propertyName, notifyId, property);
- index = m_d->m_properties.size();
+ QString result;
+ QTextStream str(&result);
+ str << "\n\n*** Sort Warning ***\nSignals and slots in QMetaObject '"
+ << mo->className()
+ << "' are not ordered correctly, this may lead to issues.\n";
+ const int methodOffset = mo->methodOffset();
+ for (int m = methodOffset, methodCount = mo->methodCount(); m < methodCount; ++m) {
+ const auto method = mo->method(m);
+ str << (m - methodOffset + 1) << (m > offendingIndex ? '!' : ' ')
+ << (method.methodType() == QMetaMethod::Signal ? " Signal " : " Slot ")
+ << method.methodSignature() << '\n';
}
- m_d->m_updated = false;
- return m_d->m_propertyOffset + index;
+ return result;
}
-int DynamicQMetaObject::DynamicQMetaObjectPrivate::getPropertyNotifyId(PySideProperty *property) const
+static void checkMethodOrder(const QMetaObject *metaObject)
{
- int notifyId = -1;
- if (property->d->notify) {
- const char *signalNotify = PySide::Property::getNotifyName(property);
- if (signalNotify) {
- const MethodData signalObject(QMetaMethod::Signal, signalNotify, "");
- notifyId = m_methods.indexOf(signalObject);
+ const int lastMethod = metaObject->methodCount() - 1;
+ for (int m = metaObject->methodOffset(); m < lastMethod; ++m) {
+ if (metaObject->method(m).methodType() == QMetaMethod::Slot
+ && metaObject->method(m + 1).methodType() == QMetaMethod::Signal) {
+ const auto message = msgMethodSortOrder(metaObject, m);
+ PyErr_WarnEx(PyExc_RuntimeWarning, qPrintable(message), 0);
+ // Prevent a warning from being turned into an error. We cannot easily unwind.
+ PyErr_Clear();
+ break;
}
}
- return notifyId;
-}
-
-void DynamicQMetaObject::addInfo(const char* key, const char* value)
-{
- m_d->m_info[key] = value;
-}
-
-void DynamicQMetaObject::addInfo(const QMap<QByteArray, QByteArray> &info)
-{
- QMap<QByteArray, QByteArray>::const_iterator i = info.constBegin();
- while (i != info.constEnd()) {
- m_d->m_info[i.key()] = i.value();
- ++i;
- }
- m_d->m_updated = false;
}
-const QMetaObject* DynamicQMetaObject::update() const
+const QMetaObject *MetaObjectBuilderPrivate::update()
{
- if (!m_d->m_updated) {
- m_d->updateMetaObject(const_cast<DynamicQMetaObject*>(this));
- m_d->m_updated = true;
+ if (!m_builder)
+ return m_baseObject;
+ if (m_cachedMetaObjects.empty() || m_dirty) {
+ m_cachedMetaObjects.push_back(m_builder->toMetaObject());
+ checkMethodOrder(m_cachedMetaObjects.back());
+ m_dirty = false;
}
- return this;
+ return m_cachedMetaObjects.back();
}
-void DynamicQMetaObject::DynamicQMetaObjectPrivate::writeMethodsData(const QList<MethodData>& methods,
- unsigned int** data,
- QByteArrayList& strings,
- int* prtIndex,
- int nullIndex,
- int flags)
+const QMetaObject *MetaObjectBuilder::update()
{
- int index = *prtIndex;
- int paramsIndex = index + methods.count() * 5;
-
- QList<MethodData>::const_iterator it = methods.begin();
-
- if (m_emptyMethod == -1)
- m_emptyMethod = registerString(EMPTY_META_METHOD, strings);
-
- for (; it != methods.end(); ++it) {
- int name_idx = 0;
- int argc = it->parameterCount();
- if (it->signature() != EMPTY_META_METHOD)
- name_idx = registerString(it->name(), strings);
- else
- name_idx = m_emptyMethod; // func name
-
- (*data)[index++] = name_idx;
- (*data)[index++] = argc; // argc (previously: arg name)
- (*data)[index++] = paramsIndex; //parameter index
- (*data)[index++] = nullIndex; // tags
- (*data)[index++] = flags | (it->methodType() == QMetaMethod::Signal ? MethodSignal : MethodSlot);
-
- if (it->methodType() == QMetaMethod::Signal)
- (*data)[13] += 1; //signal count
-
- paramsIndex += 1 + argc * 2;
- }
- *prtIndex = index;
+ return m_d->update();
}
-void DynamicQMetaObject::parsePythonType(PyTypeObject *type)
+void MetaObjectBuilderPrivate::parsePythonType(PyTypeObject *type)
{
// Get all non-QObject-derived base types in method resolution order, filtering out the types
// that can't have signals, slots or properties.
@@ -609,8 +459,8 @@ void DynamicQMetaObject::parsePythonType(PyTypeObject *type)
if (data->signatures[i])
sig += data->signatures[i];
sig += ')';
- if (d.superdata->indexOfSignal(sig) == -1)
- addSignal(sig, "void");
+ if (m_baseObject->indexOfSignal(sig) == -1)
+ m_builder->addSignal(sig);
}
}
}
@@ -634,7 +484,7 @@ void DynamicQMetaObject::parsePythonType(PyTypeObject *type)
if (Property::checkType(value)) {
// Leave the properties to be registered after signals because they may depend on
// notify signals.
- int index = d.superdata->indexOfProperty(Shiboken::String::toCString(key));
+ int index = m_baseObject->indexOfProperty(Shiboken::String::toCString(key));
if (index == -1)
properties << PropPair(Shiboken::String::toCString(key), value);
} else if (PyFunction_Check(value)) {
@@ -642,13 +492,23 @@ void DynamicQMetaObject::parsePythonType(PyTypeObject *type)
if (PyObject_HasAttr(value, slotAttrName)) {
PyObject *signatureList = PyObject_GetAttr(value, slotAttrName);
for (Py_ssize_t i = 0, i_max = PyList_Size(signatureList); i < i_max; ++i) {
- PyObject *signature = PyList_GET_ITEM(signatureList, i);
- QByteArray sig(Shiboken::String::toCString(signature));
+ PyObject *pySignature = PyList_GET_ITEM(signatureList, i);
+ QByteArray signature(Shiboken::String::toCString(pySignature));
// Split the slot type and its signature.
- QList<QByteArray> slotInfo = sig.split(' ');
- int index = d.superdata->indexOfSlot(slotInfo[1]);
- if (index == -1)
- addSlot(slotInfo[1], slotInfo[0]);
+ QByteArray type;
+ const int spacePos = signature.indexOf(' ');
+ if (spacePos != -1) {
+ type = signature.left(spacePos);
+ signature.remove(0, spacePos + 1);
+ }
+ int index = m_baseObject->indexOfSlot(signature);
+ if (index == -1) {
+ if (type.isEmpty() || type == "void") {
+ addSlot(signature);
+ } else {
+ addSlot(signature, type);
+ }
+ }
}
}
}
@@ -659,219 +519,3 @@ void DynamicQMetaObject::parsePythonType(PyTypeObject *type)
addProperty(propPair.first, propPair.second);
}
}
-
-/*!
- Allocate the meta data table.
- Returns the index in the table corresponding to the header fields count.
-*/
-int DynamicQMetaObject::DynamicQMetaObjectPrivate::createMetaData(QMetaObject* metaObj)
-{
- const int n_methods = m_methods.size();
- const int n_properties = m_properties.size();
- const int n_info = m_info.size();
-
- int header[] = {7, // revision (Used by moc, qmetaobjectbuilder and qdbus)
- 0, // class name index in m_metadata
- n_info, 0, // classinfo and classinfo index
- n_methods, 0, // method count and method list index
- n_properties, 0, // prop count and prop indexes
- 0, 0, // enum count and enum index
- 0, 0, // constructors (since revision 2)
- 0, // flags (since revision 3)
- 0}; // signal count (since revision 4)
-
- const int HEADER_LENGHT = sizeof(header)/sizeof(int);
-
- m_dataSize = HEADER_LENGHT;
- m_dataSize += n_info*2; //class info: name, value
- m_dataSize += n_methods*5; //method: name, argc, parameters, tag, flags
- m_dataSize += n_properties*4; //property: name, type, flags
- m_dataSize += 1; //eod
-
- m_dataSize += aggregateParameterCount(m_methods); // types and parameter names
-
- uint* data = reinterpret_cast<uint*>(realloc(const_cast<uint*>(metaObj->d.data), m_dataSize * sizeof(uint)));
-
- Q_ASSERT(data);
- std::memcpy(data, header, sizeof(header));
-
- metaObj->d.data = data;
-
- return HEADER_LENGHT;
-}
-
-// Writes strings to string data struct.
-// The struct consists of an array of QByteArrayData, followed by a char array
-// containing the actual strings. This format must match the one produced by
-// moc (see generator.cpp).
-void DynamicQMetaObject::DynamicQMetaObjectPrivate::writeStringData(char *out,
- const QByteArrayList& strings) const
-{
- Q_ASSERT(!(reinterpret_cast<quintptr>(out) & (Q_ALIGNOF(QByteArrayData)-1)));
-
- const int size = strings.size();
- const int offsetOfStringdataMember = size * int(sizeof(QByteArrayData));
- int stringdataOffset = 0;
- for (int i = 0; i < size; ++i)
- writeString(out, i, strings.at(i), offsetOfStringdataMember, stringdataOffset);
-}
-
-QList<MethodData>::iterator is_sorted_until(QList<MethodData>::iterator first,
- QList<MethodData>::iterator last,
- bool comp(const MethodData &m1, const MethodData &m2))
-{
- if (first != last) {
- QList<MethodData>::iterator next = first;
- while (++next != last) {
- if (comp(*next, *first))
- return next;
- ++first;
- }
- }
- return last;
-}
-
-bool is_sorted(QList<MethodData>::iterator first, QList<MethodData>::iterator last,
- bool comp(const MethodData &m1, const MethodData &m2))
-{
- return is_sorted_until(first, last, comp) == last;
-}
-
-void DynamicQMetaObject::DynamicQMetaObjectPrivate::updateMetaObject(QMetaObject* metaObj)
-{
- Q_ASSERT(!m_updated);
- m_dataSize = 0;
-
- // Recompute the size and reallocate memory
- // index is set after the last header field.
- int index = createMetaData(metaObj);
- uint *data = const_cast<uint*>(metaObj->d.data);
-
- QByteArrayList strings;
- strings.append(m_className); // register class string
- m_nullIndex = registerString(QByteArrayLiteral(""), strings); // register a null string
-
- // Write class info.
- if (!m_info.isEmpty()) {
- if (data[3] == 0)
- data[3] = index;
-
- QMap<QByteArray, QByteArray>::const_iterator i = m_info.constBegin(); //TODO: info is a hash this can fail
- while (i != m_info.constEnd()) {
- int valueIndex = registerString(i.value(), strings);
- int keyIndex = registerString(i.key(), strings);
- data[index++] = keyIndex;
- data[index++] = valueIndex;
- i++;
- }
- }
-
- // Write methods first, then properties, to be consistent with moc.
- // Write signals/slots (signals must be written first, see indexOfMethodRelative in
- // qmetaobject.cpp).
-
- QList<MethodData>::iterator it;
- // PYSIDE-315: Instead of sorting the items and maybe breaking indices,
- // we ensure that the signals and slots are sorted by the improved parsePythonType().
- // The order can only become distorted if the class is modified after creation.
- // In that case, we give a warning.
- if (!is_sorted(m_methods.begin(), m_methods.end(), sortMethodSignalSlot)) {
- const char *metaObjectName = this->m_className.data();
- PyObject *txt = PyBytes_FromFormat("\n\n*** Sort Warning ***\n"
- "Signals and slots in QMetaObject '%s' are not ordered correctly, "
- "this may lead to issues.\n", metaObjectName);
- it = m_methods.begin();
- QList<MethodData>::iterator end = m_methods.end();
- QList<MethodData>::iterator until = is_sorted_until(m_methods.begin(), m_methods.end(),
- sortMethodSignalSlot);
- for (; it != end; ++it) {
- PyObject *atxt = PyBytes_FromFormat("%d%s %s %s\n", it - m_methods.begin() + 1,
- until >= it + 1 ? " " : "!",
- it->methodType() == QMetaMethod::Signal ? "Signal" : "Slot ",
- it->signature().data() );
- PyBytes_ConcatAndDel(&txt, atxt);
- }
- PyErr_WarnEx(PyExc_RuntimeWarning, PyBytes_AsString(txt), 0);
- Py_DECREF(txt);
- // Prevent a warning from being turned into an error. We cannot easily unwind.
- PyErr_Clear();
- }
-
- if (!m_methods.empty()) {
- if (data[5] == 0)
- data[5] = index;
-
- writeMethodsData(m_methods, &data, strings, &index, m_nullIndex, AccessPublic);
- }
-
- // Write signal/slots parameters.
- if (!m_methods.empty()) {
- for (it = m_methods.begin(); it != m_methods.end(); ++it) {
- QList<QByteArray> paramTypeNames = it->parameterTypes();
- int paramCount = paramTypeNames.size();
- for (int i = -1; i < paramCount; ++i) {
- const QByteArray &typeName = (i < 0) ? it->returnType() : paramTypeNames.at(i);
- int typeInfo;
- if (QtPrivate::isBuiltinType(typeName))
- typeInfo = QMetaType::type(typeName);
- else
- typeInfo = IsUnresolvedType | registerString(typeName, strings);
- data[index++] = typeInfo;
- }
-
- // Parameter names (use a null string)
- for (int i = 0; i < paramCount; ++i) {
- data[index++] = m_nullIndex;
- }
- }
- }
-
- // Write properties.
- if (m_properties.size()) {
- if (data[7] == 0)
- data[7] = index;
-
- QList<PropertyData>::const_iterator i = m_properties.constBegin();
- while (i != m_properties.constEnd()) {
- if (i->isValid()) {
- data[index++] = registerString(i->name(), strings); // name
- } else
- data[index++] = m_nullIndex;
-
- // Find out the property type index.
- int typeInfo = m_nullIndex;
- if (i->isValid()) {
- const QByteArray &typeName = i->type();
- if (QtPrivate::isBuiltinType(typeName))
- typeInfo = QMetaType::type(typeName);
- else
- typeInfo = IsUnresolvedType | registerString(typeName, strings);
- }
- data[index++] = typeInfo; // normalized type
-
- data[index++] = i->flags();
- i++;
- }
-
- // Write properties notify.
- i = m_properties.constBegin();
- while (i != m_properties.constEnd()) {
- // Recompute notifyId, because sorting the methods might have changed the relative
- // index.
- const int notifyId = getPropertyNotifyId(i->data());
- data[index++] = notifyId >= 0 ? static_cast<uint>(notifyId) : 0; //signal notify index
- i++;
- }
- }
-
- data[index++] = 0; // the end
-
- // Create the m_metadata string.
- int size = blobSize(strings);
- char *blob =
- reinterpret_cast<char *>(realloc(reinterpret_cast<char *>(const_cast<QByteArrayData *>(metaObj->d.stringdata)), size));
- writeStringData(blob, strings);
-
- metaObj->d.stringdata = reinterpret_cast<const QByteArrayData *>(blob);
- metaObj->d.data = data;
-}
diff --git a/sources/pyside2/libpyside/dynamicqmetaobject.h b/sources/pyside2/libpyside/dynamicqmetaobject.h
index e68c7dd50..1fbe73ea4 100644
--- a/sources/pyside2/libpyside/dynamicqmetaobject.h
+++ b/sources/pyside2/libpyside/dynamicqmetaobject.h
@@ -45,39 +45,37 @@
#include <QtCore/QMetaObject>
#include <QtCore/QMetaMethod>
+class MetaObjectBuilderPrivate;
+
namespace PySide
{
-class DynamicQMetaObject : public QMetaObject
+class MetaObjectBuilder
{
- Q_DISABLE_COPY(DynamicQMetaObject)
+ Q_DISABLE_COPY(MetaObjectBuilder)
public:
- DynamicQMetaObject(const char* className, const QMetaObject* metaObject);
- DynamicQMetaObject(PyTypeObject* type, const QMetaObject* metaobject);
- ~DynamicQMetaObject();
+ MetaObjectBuilder(const char *className, const QMetaObject *metaObject);
+ MetaObjectBuilder(PyTypeObject *type, const QMetaObject *metaObject);
+ ~MetaObjectBuilder();
- int addMethod(QMetaMethod::MethodType mtype, const char* signature, const char* type);
- void removeMethod(QMetaMethod::MethodType mtype, uint index);
- int addSignal(const char* signal, const char* type = 0);
- int addSlot(const char* slot, const char* type = 0);
- int addProperty(const char* property, PyObject* data);
- void addInfo(const char* key, const char* value);
+ int indexOfMethod(QMetaMethod::MethodType mtype, const QByteArray &signature) const;
+ int indexOfProperty(const QByteArray &name) const;
+ int addSlot(const char *signature);
+ int addSlot(const char *signature, const char *type);
+ int addSignal(const char *signature);
+ void removeMethod(QMetaMethod::MethodType mtype, int index);
+ int addProperty(const char *property, PyObject *data);
+ void addInfo(const char *key, const char *value);
void addInfo(const QMap<QByteArray, QByteArray> &info);
- void removeSignal(uint idex);
- void removeSlot(uint index);
- void removeProperty(uint index);
+ void removeProperty(int index);
- const QMetaObject* update() const;
+ const QMetaObject *update();
private:
- class DynamicQMetaObjectPrivate;
- DynamicQMetaObjectPrivate* m_d;
-
- void parsePythonType(PyTypeObject *type);
+ MetaObjectBuilderPrivate *m_d;
};
-
}
#endif
diff --git a/sources/pyside2/libpyside/globalreceiverv2.cpp b/sources/pyside2/libpyside/globalreceiverv2.cpp
index a1a695759..43ce50a75 100644
--- a/sources/pyside2/libpyside/globalreceiverv2.cpp
+++ b/sources/pyside2/libpyside/globalreceiverv2.cpp
@@ -160,10 +160,8 @@ int DynamicSlotDataV2::id(const char* signature) const
int DynamicSlotDataV2::addSlot(const char* signature)
{
int index = id(signature);
- if (index == -1) {
- DynamicQMetaObject *dmo = const_cast<DynamicQMetaObject*>(reinterpret_cast<const DynamicQMetaObject*>(m_parent->metaObject()));
- index = m_signatures[signature] = dmo->addSlot(signature);
- }
+ if (index == -1)
+ index = m_signatures[signature] = m_parent->metaObjectBuilder().addSlot(signature);
return index;
}
@@ -202,7 +200,7 @@ GlobalReceiverV2::GlobalReceiverV2(PyObject *callback, SharedMap map) :
DESTROY_SIGNAL_ID = QObject::staticMetaObject.indexOfSignal("destroyed(QObject*)");
if (DESTROY_SLOT_ID == 0)
- DESTROY_SLOT_ID = m_metaObject.indexOfSlot(RECEIVER_DESTROYED_SLOT_NAME);
+ DESTROY_SLOT_ID = m_metaObject.indexOfMethod(QMetaMethod::Slot, RECEIVER_DESTROYED_SLOT_NAME);
}
@@ -306,7 +304,7 @@ QByteArray GlobalReceiverV2::hash(PyObject* callback)
const QMetaObject* GlobalReceiverV2::metaObject() const
{
- return m_metaObject.update();
+ return const_cast<GlobalReceiverV2 *>(this)->m_metaObject.update();
}
int GlobalReceiverV2::qt_metacall(QMetaObject::Call call, int id, void** args)
diff --git a/sources/pyside2/libpyside/globalreceiverv2.h b/sources/pyside2/libpyside/globalreceiverv2.h
index b12823a84..b92be93a8 100644
--- a/sources/pyside2/libpyside/globalreceiverv2.h
+++ b/sources/pyside2/libpyside/globalreceiverv2.h
@@ -135,8 +135,11 @@ public:
**/
static QByteArray hash(PyObject* callback);
+ const MetaObjectBuilder &metaObjectBuilder() const { return m_metaObject; }
+ MetaObjectBuilder &metaObjectBuilder() { return m_metaObject; }
+
private:
- DynamicQMetaObject m_metaObject;
+ MetaObjectBuilder m_metaObject;
DynamicSlotDataV2 *m_data;
QList<const QObject*> m_refs;
SharedMap m_sharedMap;
diff --git a/sources/pyside2/libpyside/pyside.cpp b/sources/pyside2/libpyside/pyside.cpp
index 856e5b92c..6e4a3efd4 100644
--- a/sources/pyside2/libpyside/pyside.cpp
+++ b/sources/pyside2/libpyside/pyside.cpp
@@ -204,7 +204,7 @@ void initDynamicMetaObject(SbkObjectType* type, const QMetaObject* base, std::si
Shiboken::ObjectType::setTypeUserData(type, userData, Shiboken::callCppDestructor<TypeUserData>);
//initialize staticQMetaObject property
- void* metaObjectPtr = &userData->mo;
+ void *metaObjectPtr = const_cast<QMetaObject *>(userData->mo.update());
static SbkConverter* converter = Shiboken::Conversions::getConverter("QMetaObject");
if (!converter)
return;
@@ -229,13 +229,13 @@ TypeUserData *retrieveTypeUserData(PyObject *pyObj)
return retrieveTypeUserData(pyTypeObj);
}
-DynamicQMetaObject *retrieveMetaObject(PyTypeObject *pyTypeObj)
+const QMetaObject *retrieveMetaObject(PyTypeObject *pyTypeObj)
{
TypeUserData *userData = retrieveTypeUserData(pyTypeObj);
- return userData ? &(userData->mo) : nullptr;
+ return userData ? userData->mo.update() : nullptr;
}
-DynamicQMetaObject *retrieveMetaObject(PyObject *pyObj)
+const QMetaObject *retrieveMetaObject(PyObject *pyObj)
{
auto pyTypeObj = PyType_Check(pyObj)
? reinterpret_cast<PyTypeObject *>(pyObj) : Py_TYPE(pyObj);
@@ -268,8 +268,7 @@ void initQObjectSubType(SbkObjectType *type, PyObject *args, PyObject * /* kwds
qWarning("Sub class of QObject not inheriting QObject!? Crash will happen when using %s.", className.constData());
return;
}
- userData->mo.update();
- initDynamicMetaObject(type, &userData->mo, userData->cppObjSize);
+ initDynamicMetaObject(type, userData->mo.update(), userData->cppObjSize);
}
PyObject* getMetaDataFromQObject(QObject* cppSelf, PyObject* self, PyObject* name)
diff --git a/sources/pyside2/libpyside/pyside_p.h b/sources/pyside2/libpyside/pyside_p.h
index 66a37fc7a..1084a40a1 100644
--- a/sources/pyside2/libpyside/pyside_p.h
+++ b/sources/pyside2/libpyside/pyside_p.h
@@ -55,7 +55,7 @@ struct TypeUserData
explicit TypeUserData(PyTypeObject* type, const QMetaObject* metaobject, std::size_t size) :
mo(type, metaobject), cppObjSize(size) {}
- DynamicQMetaObject mo;
+ MetaObjectBuilder mo;
std::size_t cppObjSize;
};
@@ -63,8 +63,8 @@ TypeUserData *retrieveTypeUserData(SbkObjectType *sbkTypeObj);
TypeUserData *retrieveTypeUserData(PyTypeObject *pyTypeObj);
TypeUserData *retrieveTypeUserData(PyObject *pyObj);
// For QML
-PYSIDE_API DynamicQMetaObject *retrieveMetaObject(PyTypeObject *pyTypeObj);
-PYSIDE_API DynamicQMetaObject *retrieveMetaObject(PyObject *pyObj);
+PYSIDE_API const QMetaObject *retrieveMetaObject(PyTypeObject *pyTypeObj);
+PYSIDE_API const QMetaObject *retrieveMetaObject(PyObject *pyObj);
} //namespace PySide
diff --git a/sources/pyside2/libpyside/pysideclassinfo.cpp b/sources/pyside2/libpyside/pysideclassinfo.cpp
index 88b2b89f5..4edf0fa91 100644
--- a/sources/pyside2/libpyside/pysideclassinfo.cpp
+++ b/sources/pyside2/libpyside/pysideclassinfo.cpp
@@ -61,7 +61,7 @@ static PyType_Slot PySideClassInfoType_slots[] = {
{Py_tp_init, (void *)classInfoTpInit},
{Py_tp_new, (void *)classInfoTpNew},
{Py_tp_free, (void *)classInfoFree},
- {Py_tp_dealloc, (void *)SbkDummyDealloc},
+ {Py_tp_dealloc, (void *)object_dealloc},
{0, 0}
};
static PyType_Spec PySideClassInfoType_spec = {
@@ -108,8 +108,9 @@ PyObject *classCall(PyObject *self, PyObject *args, PyObject * /* kw */)
PyTypeObject *klassType = reinterpret_cast<PyTypeObject*>(klass);
if (Shiboken::ObjectType::checkType(klassType)) {
- if (PySide::DynamicQMetaObject *mo = PySide::retrieveMetaObject(klassType)) {
- mo->addInfo(PySide::ClassInfo::getMap(data));
+ if (auto userData = PySide::retrieveTypeUserData(klassType)) {
+ PySide::MetaObjectBuilder &mo = userData->mo;
+ mo.addInfo(PySide::ClassInfo::getMap(data));
pData->m_alreadyWrapped = true;
validClass = true;
}
diff --git a/sources/pyside2/libpyside/pysidemetafunction.cpp b/sources/pyside2/libpyside/pysidemetafunction.cpp
index 80496764d..4cdc7ec16 100644
--- a/sources/pyside2/libpyside/pysidemetafunction.cpp
+++ b/sources/pyside2/libpyside/pysidemetafunction.cpp
@@ -61,7 +61,7 @@ static PyType_Slot PySideMetaFunctionType_slots[] = {
{Py_tp_call, (void *)functionCall},
{Py_tp_new, (void *)PyType_GenericNew},
{Py_tp_free, (void *)functionFree},
- {Py_tp_dealloc, (void *)SbkDummyDealloc},
+ {Py_tp_dealloc, (void *)object_dealloc},
{0, 0}
};
static PyType_Spec PySideMetaFunctionType_spec = {
diff --git a/sources/pyside2/libpyside/pysideqflags.cpp b/sources/pyside2/libpyside/pysideqflags.cpp
index f948ecac7..cb57031b0 100644
--- a/sources/pyside2/libpyside/pysideqflags.cpp
+++ b/sources/pyside2/libpyside/pysideqflags.cpp
@@ -152,7 +152,7 @@ namespace QFlags
#endif
{Py_tp_new, (void *)PySideQFlagsNew},
{Py_tp_richcompare, (void *)PySideQFlagsRichCompare},
- {Py_tp_dealloc, (void *)SbkDummyDealloc},
+ {Py_tp_dealloc, (void *)object_dealloc},
{0, 0}
};
static PyType_Spec SbkNewQFlagsType_spec = {
diff --git a/sources/pyside2/libpyside/pysidesignal.cpp b/sources/pyside2/libpyside/pysidesignal.cpp
index 3b21b16da..e7fd389a8 100644
--- a/sources/pyside2/libpyside/pysidesignal.cpp
+++ b/sources/pyside2/libpyside/pysidesignal.cpp
@@ -109,7 +109,7 @@ static PyType_Slot PySideSignalMetaType_slots[] = {
{Py_tp_methods, (void *)Signal_methods},
{Py_tp_base, (void *)&PyType_Type},
{Py_tp_free, (void *)PyObject_GC_Del},
- {Py_tp_dealloc, (void *)SbkDummyDealloc},
+ {Py_tp_dealloc, (void *)object_dealloc},
{0, 0}
};
static PyType_Spec PySideSignalMetaType_spec = {
@@ -141,7 +141,7 @@ static PyType_Slot PySideSignalType_slots[] = {
{Py_tp_init, (void *)signalTpInit},
{Py_tp_new, (void *)PyType_GenericNew},
{Py_tp_free, (void *)signalFree},
- {Py_tp_dealloc, (void *)SbkDummyDealloc},
+ {Py_tp_dealloc, (void *)object_dealloc},
{0, 0}
};
static PyType_Spec PySideSignalType_spec = {
@@ -180,7 +180,7 @@ static PyType_Slot PySideSignalInstanceType_slots[] = {
{Py_tp_methods, (void *)SignalInstance_methods},
{Py_tp_new, (void *)PyType_GenericNew},
{Py_tp_free, (void *)signalInstanceFree},
- {Py_tp_dealloc, (void *)SbkDummyDealloc},
+ {Py_tp_dealloc, (void *)object_dealloc},
{0, 0}
};
static PyType_Spec PySideSignalInstanceType_spec = {
diff --git a/sources/pyside2/libpyside/pysideslot.cpp b/sources/pyside2/libpyside/pysideslot.cpp
index 0dff3bafb..6f6658cf8 100644
--- a/sources/pyside2/libpyside/pysideslot.cpp
+++ b/sources/pyside2/libpyside/pysideslot.cpp
@@ -67,7 +67,7 @@ static PyType_Slot PySideSlotType_slots[] = {
{Py_tp_call, (void *)slotCall},
{Py_tp_init, (void *)slotTpInit},
{Py_tp_new, (void *)PyType_GenericNew},
- {Py_tp_dealloc, (void *)SbkDummyDealloc},
+ {Py_tp_dealloc, (void *)object_dealloc},
{0, 0}
};
static PyType_Spec PySideSlotType_spec = {
diff --git a/sources/pyside2/libpyside/pysideweakref.cpp b/sources/pyside2/libpyside/pysideweakref.cpp
index a0b7f4aaa..6b5073db8 100644
--- a/sources/pyside2/libpyside/pysideweakref.cpp
+++ b/sources/pyside2/libpyside/pysideweakref.cpp
@@ -53,7 +53,7 @@ static PyObject* CallableObject_call(PyObject* callable_object, PyObject* args,
static PyType_Slot PySideCallableObjectType_slots[] = {
{Py_tp_call, (void *)CallableObject_call},
- {Py_tp_dealloc, (void *)SbkDummyDealloc},
+ {Py_tp_dealloc, (void *)object_dealloc},
{0, 0}
};
static PyType_Spec PySideCallableObjectType_spec = {
diff --git a/sources/pyside2/libpyside/signalmanager.cpp b/sources/pyside2/libpyside/signalmanager.cpp
index f505fde5a..8925ffd35 100644
--- a/sources/pyside2/libpyside/signalmanager.cpp
+++ b/sources/pyside2/libpyside/signalmanager.cpp
@@ -90,7 +90,7 @@ namespace {
static void destroyMetaObject(PyObject* obj)
{
void* ptr = PyCapsule_GetPointer(obj, 0);
- PySide::DynamicQMetaObject* meta = reinterpret_cast<PySide::DynamicQMetaObject*>(ptr);
+ auto meta = reinterpret_cast<PySide::MetaObjectBuilder*>(ptr);
SbkObject* wrapper = Shiboken::BindingManager::instance().retrieveWrapper(meta);
if (wrapper)
Shiboken::BindingManager::instance().releaseWrapper(wrapper);
@@ -100,7 +100,7 @@ namespace {
#else
static void destroyMetaObject(void* obj)
{
- PySide::DynamicQMetaObject* meta = reinterpret_cast<PySide::DynamicQMetaObject*>(obj);
+ auto meta = reinterpret_cast<PySide::MetaObjectBuilder*>(obj);
SbkObject* wrapper = Shiboken::BindingManager::instance().retrieveWrapper(meta);
if (wrapper)
Shiboken::BindingManager::instance().releaseWrapper(wrapper);
@@ -549,6 +549,19 @@ bool SignalManager::registerMetaMethod(QObject* source, const char* signature, Q
return (ret != -1);
}
+static MetaObjectBuilder *metaBuilderFromDict(PyObject* dict)
+{
+ if (!dict || !PyDict_Contains(dict, metaObjectAttr))
+ return nullptr;
+
+ PyObject *pyBuilder = PyDict_GetItem(dict, metaObjectAttr);
+#ifdef IS_PY3K
+ return reinterpret_cast<MetaObjectBuilder *>(PyCapsule_GetPointer(pyBuilder, nullptr));
+#else
+ return reinterpret_cast<MetaObjectBuilder *>(PyCObject_AsVoidPtr(pyBuilder));
+#endif
+}
+
int SignalManager::registerMetaMethodGetIndex(QObject* source, const char* signature, QMetaMethod::MethodType type)
{
if (!source) {
@@ -565,13 +578,13 @@ int SignalManager::registerMetaMethodGetIndex(QObject* source, const char* signa
qWarning() << "Invalid Signal signature:" << signature;
return -1;
} else {
- DynamicQMetaObject *dmo = 0;
PyObject *pySelf = reinterpret_cast<PyObject*>(self);
PyObject* dict = self->ob_dict;
+ MetaObjectBuilder *dmo = metaBuilderFromDict(dict);
// Create a instance meta object
- if (!dict || !PyDict_Contains(dict, metaObjectAttr)) {
- dmo = new DynamicQMetaObject(Py_TYPE(pySelf), metaObject);
+ if (!dmo) {
+ dmo = new MetaObjectBuilder(Py_TYPE(pySelf), metaObject);
#ifdef IS_PY3K
PyObject* pyDmo = PyCapsule_New(dmo, 0, destroyMetaObject);
#else
@@ -580,8 +593,6 @@ int SignalManager::registerMetaMethodGetIndex(QObject* source, const char* signa
PyObject_SetAttr(pySelf, metaObjectAttr, pyDmo);
Py_DECREF(pyDmo);
- } else {
- dmo = reinterpret_cast<DynamicQMetaObject*>(const_cast<QMetaObject*>(metaObject));
}
if (type == QMetaMethod::Signal)
@@ -596,24 +607,13 @@ int SignalManager::registerMetaMethodGetIndex(QObject* source, const char* signa
const QMetaObject* SignalManager::retrieveMetaObject(PyObject *self)
{
Shiboken::GilState gil;
- DynamicQMetaObject *mo = 0;
Q_ASSERT(self);
- PyObject* dict = reinterpret_cast<SbkObject*>(self)->ob_dict;
- if (dict && PyDict_Contains(dict, metaObjectAttr)) {
- PyObject *pyMo = PyDict_GetItem(dict, metaObjectAttr);
-
-#ifdef IS_PY3K
- mo = reinterpret_cast<DynamicQMetaObject*>(PyCapsule_GetPointer(pyMo, 0));
-#else
- mo = reinterpret_cast<DynamicQMetaObject*>(PyCObject_AsVoidPtr(pyMo));
-#endif
- } else {
- mo = PySide::retrieveMetaObject(self);
- }
+ MetaObjectBuilder *builder = metaBuilderFromDict(reinterpret_cast<SbkObject*>(self)->ob_dict);
+ if (!builder)
+ builder = &(retrieveTypeUserData(self)->mo);
- mo->update();
- return mo;
+ return builder->update();
}
namespace {
diff --git a/sources/pyside2/tests/QtCore/qmetaobject_test.py b/sources/pyside2/tests/QtCore/qmetaobject_test.py
index 12b5312a6..73ab81c7c 100644
--- a/sources/pyside2/tests/QtCore/qmetaobject_test.py
+++ b/sources/pyside2/tests/QtCore/qmetaobject_test.py
@@ -78,6 +78,12 @@ class qmetaobject_test(unittest.TestCase):
#self.assertTrue(slot_index != signal_index)
+ # PYSIDE-784, plain Qt objects should not have intermediary
+ # metaObjects.
+ def test_PlainQObject(self):
+ timer = QTimer()
+ self.assertEqual(timer.metaObject().superClass().className(),
+ "QObject")
if __name__ == '__main__':
unittest.main()
diff --git a/sources/pyside2/tests/QtWidgets/qwidget_test.py b/sources/pyside2/tests/QtWidgets/qwidget_test.py
index 1e8387d11..028751ba7 100644
--- a/sources/pyside2/tests/QtWidgets/qwidget_test.py
+++ b/sources/pyside2/tests/QtWidgets/qwidget_test.py
@@ -26,6 +26,7 @@
##
#############################################################################
+import sys
import unittest
from PySide2.QtWidgets import QWidget, QMainWindow
@@ -35,6 +36,17 @@ class QWidgetInherit(QMainWindow):
def __init__(self):
QWidget.__init__(self)
+class NativeEventTestWidget(QWidget):
+
+ nativeEventCount = 0
+
+ def __init__(self):
+ QWidget.__init__(self)
+
+ def nativeEvent(self, eventType, message):
+ self.nativeEventCount = self.nativeEventCount + 1
+ return [False, 0]
+
class QWidgetTest(UsesQApplication):
def testInheritance(self):
@@ -44,12 +56,19 @@ class QWidgetVisible(UsesQApplication):
def testBasic(self):
# Also related to bug #244, on existence of setVisible'''
- widget = QWidget()
+ widget = NativeEventTestWidget()
self.assertTrue(not widget.isVisible())
widget.setVisible(True)
self.assertTrue(widget.isVisible())
self.assertTrue(widget.winId() is not 0)
-
+ # skip this test on macOS since no native events are received
+ if sys.platform == 'darwin':
+ return
+ for i in range(10):
+ if widget.nativeEventCount > 0:
+ break
+ self.app.processEvents()
+ self.assertTrue(widget.nativeEventCount > 0)
if __name__ == '__main__':
unittest.main()
diff --git a/sources/pyside2/tests/pysidetest/CMakeLists.txt b/sources/pyside2/tests/pysidetest/CMakeLists.txt
index 5b7f0fde1..119553fad 100644
--- a/sources/pyside2/tests/pysidetest/CMakeLists.txt
+++ b/sources/pyside2/tests/pysidetest/CMakeLists.txt
@@ -66,7 +66,9 @@ make_path(testbinding_include_dirs ${pyside2_BINARY_DIR}
make_path(testbinding_typesystem_path ${pyside2_SOURCE_DIR}
${pyside2_BINARY_DIR})
-add_custom_command(OUTPUT ${testbinding_SRC}
+add_custom_command(
+OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log"
+BYPRODUCTS ${testbinding_SRC}
COMMAND ${SHIBOKEN_BINARY} ${GENERATOR_EXTRA_FLAGS}
${CMAKE_CURRENT_SOURCE_DIR}/pysidetest_global.h
--include-paths=${testbinding_include_dirs}
@@ -116,6 +118,7 @@ target_link_libraries(testbinding
${SBK_PYTHON_LIBRARIES})
add_dependencies(testbinding pyside2 QtCore QtGui QtWidgets pysidetest)
+create_generator_target(testbinding)
PYSIDE_TEST(decoratedslot_test.py)
# Will always crash when built against Qt 5.6, no point in running it.
diff --git a/sources/shiboken2/generator/generator.cpp b/sources/shiboken2/generator/generator.cpp
index 85a8c4769..8b37b44e0 100644
--- a/sources/shiboken2/generator/generator.cpp
+++ b/sources/shiboken2/generator/generator.cpp
@@ -395,20 +395,7 @@ bool Generator::generateFileForContext(GeneratorContext &context)
generateClass(fileOut.stream, context);
- FileOut::State state = fileOut.done();
- switch (state) {
- case FileOut::Failure:
- return false;
- case FileOut::Unchanged:
- // Even if contents is unchanged, the last file modification time should be updated,
- // so that the build system can rely on the fact the generated file is up-to-date.
- fileOut.touch();
- break;
- case FileOut::Success:
- break;
- }
-
- return true;
+ return fileOut.done() != FileOut::Failure;
}
QString Generator::getFileNameBaseForSmartPointer(const AbstractMetaType *smartPointerType,
diff --git a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
index 6d16e1bfb..99947d347 100644
--- a/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
+++ b/sources/shiboken2/generator/shiboken2/cppgenerator.cpp
@@ -3801,7 +3801,7 @@ void CppGenerator::writeClassDefinition(QTextStream &s,
if (metaClass->isNamespace() || metaClass->hasPrivateDestructor()) {
tp_dealloc = metaClass->hasPrivateDestructor() ?
QLatin1String("SbkDeallocWrapperWithPrivateDtor") :
- QLatin1String("SbkDummyDealloc /* PYSIDE-595: Prevent replacement of \"0\" with subtype_dealloc. */");
+ QLatin1String("object_dealloc /* PYSIDE-832: Prevent replacement of \"0\" with subtype_dealloc. */");
tp_init = QLatin1String("0");
} else {
QString deallocClassName;
@@ -5732,19 +5732,7 @@ bool CppGenerator::finishGeneration()
s << "SBK_MODULE_INIT_FUNCTION_END" << endl;
- switch (file.done()) {
- case FileOut::Failure:
- return false;
- case FileOut::Unchanged:
- // Even if contents is unchanged, the last file modification time should be updated,
- // so that the build system can rely on the fact the generated file is up-to-date.
- file.touch();
- break;
- case FileOut::Success:
- break;
- }
-
- return true;
+ return file.done() != FileOut::Failure;
}
static ArgumentOwner getArgumentOwner(const AbstractMetaFunction* func, int argIndex)
diff --git a/sources/shiboken2/generator/shiboken2/headergenerator.cpp b/sources/shiboken2/generator/shiboken2/headergenerator.cpp
index 9bb5fafde..8881d71f4 100644
--- a/sources/shiboken2/generator/shiboken2/headergenerator.cpp
+++ b/sources/shiboken2/generator/shiboken2/headergenerator.cpp
@@ -32,6 +32,8 @@
#include <reporthandler.h>
#include <fileout.h>
+#include <algorithm>
+
#include <QtCore/QDir>
#include <QtCore/QTextStream>
#include <QtCore/QVariant>
@@ -378,7 +380,12 @@ bool HeaderGenerator::finishGeneration()
macrosStream << "// Type indices\nenum : int {\n";
AbstractMetaEnumList globalEnums = this->globalEnums();
- const AbstractMetaClassList &classList = classes();
+ AbstractMetaClassList classList = classes();
+
+ std::sort(classList.begin(), classList.end(), [](AbstractMetaClass *a, AbstractMetaClass* b) {
+ return a->typeEntry()->sbkIndex() < b->typeEntry()->sbkIndex();
+ });
+
for (const AbstractMetaClass *metaClass : classList) {
writeTypeIndexValueLines(macrosStream, metaClass);
lookForEnumsInClassesNotToBeGenerated(globalEnums, metaClass);
diff --git a/sources/shiboken2/libshiboken/basewrapper.cpp b/sources/shiboken2/libshiboken/basewrapper.cpp
index 2f5f27989..c9e3b9d1b 100644
--- a/sources/shiboken2/libshiboken/basewrapper.cpp
+++ b/sources/shiboken2/libshiboken/basewrapper.cpp
@@ -447,8 +447,10 @@ PyObject* SbkQAppTpNew(PyTypeObject* subtype, PyObject *, PyObject *)
}
void
-SbkDummyDealloc(PyObject *)
-{}
+object_dealloc(PyObject *self)
+{
+ Py_TYPE(self)->tp_free(self);
+}
PyObject *
SbkDummyNew(PyTypeObject *type, PyObject*, PyObject*)
diff --git a/sources/shiboken2/libshiboken/basewrapper.h b/sources/shiboken2/libshiboken/basewrapper.h
index f8940b842..65849d783 100644
--- a/sources/shiboken2/libshiboken/basewrapper.h
+++ b/sources/shiboken2/libshiboken/basewrapper.h
@@ -109,17 +109,15 @@ LIBSHIBOKEN_API PyObject* SbkObjectTpNew(PyTypeObject* subtype, PyObject*, PyObj
LIBSHIBOKEN_API PyObject* SbkQAppTpNew(PyTypeObject *subtype, PyObject *args, PyObject *kwds);
/**
- * PYSIDE-595: Use a null deallocator instead of nullptr.
+ * PYSIDE-832: Use object_dealloc instead of nullptr.
*
* When moving to heaptypes, we were struck by a special default behavior of
* PyType_FromSpecWithBases that inserts subtype_dealloc when tp_dealloc is
- * nullptr. To prevent inserting this, we use a null deallocator that is there
- * as a placeholder.
- *
- * The same holds for a null tp_new. We use one that raises the right error.
+ * nullptr. But the default before conversion to heaptypes was to assign
+ * object_dealloc. This seems to be a bug in the Limited API.
*/
-LIBSHIBOKEN_API void SbkDummyDealloc(PyObject*);
-LIBSHIBOKEN_API PyObject *SbkDummyNew(PyTypeObject *type, PyObject*, PyObject*);
+LIBSHIBOKEN_API void object_dealloc(PyObject *);
+LIBSHIBOKEN_API PyObject *SbkDummyNew(PyTypeObject *type, PyObject *, PyObject *);
} // extern "C"
diff --git a/sources/shiboken2/libshiboken/pep384impl_doc.rst b/sources/shiboken2/libshiboken/pep384impl_doc.rst
index 9974f737b..2844249ad 100644
--- a/sources/shiboken2/libshiboken/pep384impl_doc.rst
+++ b/sources/shiboken2/libshiboken/pep384impl_doc.rst
@@ -426,11 +426,16 @@ many headaches::
type->tp_dealloc = subtype_dealloc;
}
-So, if you think you have no ``tp_dealloc`` field set, you will unwantedly
-get ``subtype_dealloc``, which in the case of PySide always was wrong!
+In fact, before the move to the new API, the ``PyType_Ready`` function
+filled empty ``tp_dealloc`` fields with ``object_dealloc``. And the code
+that has been written with that in mind now becomes pretty wrong if suddenly
+``subtype_dealloc`` is used.
+
+The way out was to explicitly provide an ``object_dealloc`` function.
+This would then again impose a problem, because ``object_dealloc`` is not
+public. Writing our own version is easy, but it again needs access to
+type objects. But fortunately, we have broken this rule, already...
-The way out was to use a dummy function that has no effect other than
-being something not NULL.
* The new types are only partially allocated
diff --git a/sources/shiboken2/libshiboken/sbkenum.cpp b/sources/shiboken2/libshiboken/sbkenum.cpp
index 4d516f1e8..3c6582adc 100644
--- a/sources/shiboken2/libshiboken/sbkenum.cpp
+++ b/sources/shiboken2/libshiboken/sbkenum.cpp
@@ -512,7 +512,7 @@ static PyType_Slot SbkNewType_slots[] = {
{Py_nb_index, (void *)enum_int},
{Py_tp_richcompare, (void *)enum_richcompare},
{Py_tp_hash, (void *)enum_hash},
- {Py_tp_dealloc, (void *)SbkDummyDealloc},
+ {Py_tp_dealloc, (void *)object_dealloc},
{0, 0}
};
static PyType_Spec SbkNewType_spec = {
diff --git a/sources/shiboken2/libshiboken/voidptr.cpp b/sources/shiboken2/libshiboken/voidptr.cpp
index 3a0dbb434..0d7b6b9cd 100644
--- a/sources/shiboken2/libshiboken/voidptr.cpp
+++ b/sources/shiboken2/libshiboken/voidptr.cpp
@@ -224,7 +224,7 @@ static PyType_Slot SbkVoidPtrType_slots[] = {
{Py_tp_richcompare, (void *)SbkVoidPtrObject_richcmp},
{Py_tp_init, (void *)SbkVoidPtrObject_init},
{Py_tp_new, (void *)SbkVoidPtrObject_new},
- {Py_tp_dealloc, (void *)SbkDummyDealloc},
+ {Py_tp_dealloc, (void *)object_dealloc},
{0, 0}
};
static PyType_Spec SbkVoidPtrType_spec = {
diff --git a/sources/shiboken2/shibokenmodule/CMakeLists.txt b/sources/shiboken2/shibokenmodule/CMakeLists.txt
index 517aecba8..20baf9f7e 100644
--- a/sources/shiboken2/shibokenmodule/CMakeLists.txt
+++ b/sources/shiboken2/shibokenmodule/CMakeLists.txt
@@ -12,7 +12,9 @@ set(shibokenmodule_TYPESYSTEM
${CMAKE_CURRENT_SOURCE_DIR}/typesystem_shiboken.xml
)
-add_custom_command(OUTPUT ${sample_SRC}
+add_custom_command(
+OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log"
+BYPRODUCTS ${sample_SRC}
# Note: shiboken2 is an executable target. By not specifying its explicit
# path, CMAKE figures it out, itself!
# This fixes an issue with Visual Studio, see https://github.com/PySide/shiboken2/pull/11
@@ -39,6 +41,7 @@ target_link_libraries(shibokenmodule
libshiboken)
add_dependencies(shibokenmodule shiboken2)
+create_generator_target(shibokenmodule)
install(TARGETS shibokenmodule DESTINATION ${PYTHON_SITE_PACKAGES}/shiboken2)
diff --git a/sources/shiboken2/tests/minimalbinding/CMakeLists.txt b/sources/shiboken2/tests/minimalbinding/CMakeLists.txt
index b8b6417d1..ec674b56b 100644
--- a/sources/shiboken2/tests/minimalbinding/CMakeLists.txt
+++ b/sources/shiboken2/tests/minimalbinding/CMakeLists.txt
@@ -15,7 +15,9 @@ ${CMAKE_CURRENT_BINARY_DIR}/minimal/minbooluser_wrapper.cpp
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/minimal-binding.txt.in"
"${CMAKE_CURRENT_BINARY_DIR}/minimal-binding.txt" @ONLY)
-add_custom_command(OUTPUT ${minimal_SRC}
+add_custom_command(
+OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log"
+BYPRODUCTS ${minimal_SRC}
COMMAND shiboken2 --project-file=${CMAKE_CURRENT_BINARY_DIR}/minimal-binding.txt ${GENERATOR_EXTRA_FLAGS}
DEPENDS ${minimal_TYPESYSTEM} ${CMAKE_CURRENT_SOURCE_DIR}/global.h shiboken2
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
@@ -38,3 +40,4 @@ target_link_libraries(minimal
libminimal
${SBK_PYTHON_LIBRARIES}
libshiboken)
+create_generator_target(minimal)
diff --git a/sources/shiboken2/tests/otherbinding/CMakeLists.txt b/sources/shiboken2/tests/otherbinding/CMakeLists.txt
index 186766b41..0be66f797 100644
--- a/sources/shiboken2/tests/otherbinding/CMakeLists.txt
+++ b/sources/shiboken2/tests/otherbinding/CMakeLists.txt
@@ -17,7 +17,9 @@ ${CMAKE_CURRENT_BINARY_DIR}/other/other_module_wrapper.cpp
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/other-binding.txt.in"
"${CMAKE_CURRENT_BINARY_DIR}/other-binding.txt" @ONLY)
-add_custom_command(OUTPUT ${other_SRC}
+add_custom_command(
+OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log"
+BYPRODUCTS ${other_SRC}
COMMAND shiboken2 --project-file=${CMAKE_CURRENT_BINARY_DIR}/other-binding.txt ${GENERATOR_EXTRA_FLAGS}
DEPENDS ${other_TYPESYSTEM} ${CMAKE_CURRENT_SOURCE_DIR}/global.h shiboken2
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
@@ -48,4 +50,5 @@ target_link_libraries(other
libshiboken)
add_dependencies(other sample)
+create_generator_target(other)
diff --git a/sources/shiboken2/tests/samplebinding/CMakeLists.txt b/sources/shiboken2/tests/samplebinding/CMakeLists.txt
index ca737ca08..7f4bec5f4 100644
--- a/sources/shiboken2/tests/samplebinding/CMakeLists.txt
+++ b/sources/shiboken2/tests/samplebinding/CMakeLists.txt
@@ -128,7 +128,9 @@ ${CMAKE_CURRENT_BINARY_DIR}/sample/union_wrapper.cpp
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/sample-binding.txt.in"
"${CMAKE_CURRENT_BINARY_DIR}/sample-binding.txt" @ONLY)
-add_custom_command(OUTPUT ${sample_SRC}
+add_custom_command(
+OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log"
+BYPRODUCTS ${sample_SRC}
COMMAND shiboken2 --project-file=${CMAKE_CURRENT_BINARY_DIR}/sample-binding.txt ${GENERATOR_EXTRA_FLAGS}
DEPENDS ${sample_TYPESYSTEM} ${CMAKE_CURRENT_SOURCE_DIR}/global.h shiboken2
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
@@ -152,3 +154,4 @@ target_link_libraries(sample
libsample
${SBK_PYTHON_LIBRARIES}
libshiboken)
+create_generator_target(sample)
diff --git a/sources/shiboken2/tests/smartbinding/CMakeLists.txt b/sources/shiboken2/tests/smartbinding/CMakeLists.txt
index faaa797b6..43888fae2 100644
--- a/sources/shiboken2/tests/smartbinding/CMakeLists.txt
+++ b/sources/shiboken2/tests/smartbinding/CMakeLists.txt
@@ -16,7 +16,9 @@ ${CMAKE_CURRENT_BINARY_DIR}/smart/registry_wrapper.cpp
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/smart-binding.txt.in"
"${CMAKE_CURRENT_BINARY_DIR}/smart-binding.txt" @ONLY)
-add_custom_command(OUTPUT ${smart_SRC}
+add_custom_command(
+OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log"
+BYPRODUCTS ${smart_SRC}
COMMAND shiboken2 --project-file=${CMAKE_CURRENT_BINARY_DIR}/smart-binding.txt ${GENERATOR_EXTRA_FLAGS}
DEPENDS ${smart_TYPESYSTEM} ${CMAKE_CURRENT_SOURCE_DIR}/global.h shiboken2
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
@@ -40,3 +42,4 @@ target_link_libraries(smart
libsmart
${SBK_PYTHON_LIBRARIES}
libshiboken)
+create_generator_target(smart)