Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions qt_gui/src/qt_gui/about_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
import platform
import sys

from packaging.version import Version

from python_qt_binding import QT_BINDING, QT_BINDING_MODULES, QT_BINDING_VERSION
from python_qt_binding.QtCore import QObject, qVersion
from python_qt_binding.QtWidgets import QMessageBox
Expand Down Expand Up @@ -99,6 +101,16 @@ def show(self):

text += '.</p>'

if Version(QT_BINDING_VERSION) < Version('6.0.0'):
no_icon = QMessageBox.NoIcon
ok = QMessageBox.Ok
else:
no_icon = QMessageBox.Icon.NoIcon
ok = QMessageBox.StandardButton.Ok

mb = QMessageBox(
QMessageBox.NoIcon, self.tr('About rqt'), text, QMessageBox.Ok, self.parent())
mb.exec_()
no_icon, self.tr('About rqt'), text, ok, self.parent())
if Version(QT_BINDING_VERSION) < Version('6.0.0'):
mb.exec_()
else:
mb.exec()
5 changes: 4 additions & 1 deletion qt_gui/src/qt_gui/perspective_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,10 @@ def __init__(self, settings, application_context):
def set_menu(self, menu):
self._menu_manager = MenuManager(menu)
self._perspective_mapper = QSignalMapper(menu)
self._perspective_mapper.mapped[str].connect(self.switch_perspective)
if Version(QT_BINDING_VERSION) <= Version('5.14.0'):
self._perspective_mapper.mapped[str].connect(self.switch_perspective)
else:
self._perspective_mapper.mappedString[str].connect(self.switch_perspective)

# generate menu
create_action = QAction('&Create perspective...', self._menu_manager.menu)
Expand Down
5 changes: 4 additions & 1 deletion qt_gui/src/qt_gui/plugin_menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,10 @@ def __init__(self, menu_bar, plugin_manager):
action.setVisible(False)
self._running_menu_manager.add_item(action)
self._running_mapper = QSignalMapper(running_menu)
self._running_mapper.mapped[str].connect(self.unload_plugin_signal)
if Version(QT_BINDING_VERSION) <= Version('5.14.0'):
self._running_mapper.mapped[str].connect(self.unload_plugin_signal)
else:
self._running_mapper.mappedString[str].connect(self.unload_plugin_signal)

self._instances = {}

Expand Down
12 changes: 6 additions & 6 deletions qt_gui_cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ if(WIN32)
endif()

find_package(pluginlib REQUIRED)
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets Core)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Core)
include(cmake/qt_gui_cpp-extras.cmake)
find_package(Qt${qt_gui_cpp_USE_QT_MAJOR_VERSION} REQUIRED COMPONENTS Widgets Core)
find_package(TinyXML2 REQUIRED)

ament_python_install_package(${PROJECT_NAME}
Expand All @@ -44,7 +44,7 @@ set(qt_gui_cpp_HDRS
include/qt_gui_cpp/plugin_context.hpp
)

if(${QT_VERSION_MAJOR} GREATER "5")
if(${qt_gui_cpp_USE_QT_MAJOR_VERSION} GREATER "5")
qt_standard_project_setup()
qt_wrap_cpp(qt_gui_cpp_MOCS ${qt_gui_cpp_HDRS})
else()
Expand All @@ -62,8 +62,8 @@ target_link_libraries(${PROJECT_NAME}
PUBLIC
${QT_QTCORE_LIBRARY}
${QT_QTGUI_LIBRARY}
Qt${QT_VERSION_MAJOR}::Widgets
Qt${QT_VERSION_MAJOR}::Core
Qt${qt_gui_cpp_USE_QT_MAJOR_VERSION}::Widgets
Qt${qt_gui_cpp_USE_QT_MAJOR_VERSION}::Core
pluginlib::pluginlib
tinyxml2::tinyxml2
)
Expand All @@ -84,7 +84,7 @@ install(
DESTINATION include/${PROJECT_NAME}
)

if(${QT_VERSION_MAJOR} GREATER "5")
if(${qt_gui_cpp_USE_QT_MAJOR_VERSION} GREATER "5")
ament_export_dependencies(Qt6)
endif()
ament_export_dependencies(pluginlib TinyXML2)
Expand Down
4 changes: 3 additions & 1 deletion qt_gui_cpp/cmake/qt_gui_cpp-extras.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,6 @@
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

set(qt_gui_cpp_USE_QT_MAJOR_VERSION 6)

find_package(python_qt_binding QUIET)
set(qt_gui_cpp_USE_QT_MAJOR_VERSION "${python_qt_binding_QT_MAJOR_VERSION}")
74 changes: 29 additions & 45 deletions qt_gui_cpp/src/qt_gui_cpp_shiboken/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@

# Cannot use shiboken because of bugs in Debian and Ubuntu
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1131536
# https://bugs.launchpad.net/ubuntu/+source/pyside6/+bug/2146611
return()

find_package(Qt${QT_VERSION_MAJOR}Widgets REQUIRED)

set(qt_gui_cpp_shiboken_QT_COMPONENTS
Expand Down Expand Up @@ -46,28 +52,13 @@ if(${QT_VERSION_MAJOR} GREATER "5")
set(qt_gui_cpp_BINDINGS "${qt_gui_cpp_BINDINGS}" PARENT_SCOPE)
# Find required packages
find_package(Python COMPONENTS Interpreter Development REQUIRED)
# On RHEL and some other distros, Python wheels and site-packages may be installed under 'lib64'
# instead of 'lib'. The FindPython CMake module may set Python_SITELIB to 'lib', which is incorrect
# for these cases. To ensure compatibility, we override Python_SITELIB by querying Python directly.
# This guarantees the correct site-packages path is used regardless of platform or Python build.
execute_process(
COMMAND ${Python_EXECUTABLE} -c
"import site; print(next(p for p in site.getsitepackages() if 'site-packages' in p))"
OUTPUT_VARIABLE Python_SITELIB
OUTPUT_STRIP_TRAILING_WHITESPACE
)

list(APPEND CMAKE_PREFIX_PATH
"${Python_SITELIB}/shiboken6_generator/lib/cmake"
)
find_package(Shiboken6Tools REQUIRED)

set(shiboken_extra_options_str "")
foreach(dir ${class_loader_INCLUDE_DIRS} ${pluginlib_INCLUDE_DIRS} ${rcutils_INCLUDE_DIRS} ${rcpputils_INCLUDE_DIRS})
list(APPEND shiboken_extra_options_str "-I\"${dir}\"")
endforeach()


message(shiboken_extra_options_str ${shiboken_extra_options_str})

# Create Python bindings using Shiboken6Tools function
Expand All @@ -88,39 +79,32 @@ if(${QT_VERSION_MAJOR} GREATER "5")
else()
include(${python_qt_binding_DIR}/shiboken_helper.cmake)
if(shiboken_helper_FOUND)
if(Shiboken_VERSION VERSION_GREATER "1.1.1")
# shiboken 1.1.2 and higher will segfault until https://bugreports.qt-project.org/browse/PYSIDE-218 is fixed
message(WARNING "Shiboken version ${Shiboken_VERSION} would segfault when trying to process qt_gui_cpp "
"(see https://bugreports.qt-project.org/browse/PYSIDE-218)"
" Therefore shiboken bindings are being skipped.")
else()
list(APPEND qt_gui_cpp_BINDINGS "shiboken")
set(qt_gui_cpp_BINDINGS "${qt_gui_cpp_BINDINGS}" PARENT_SCOPE)
list(APPEND qt_gui_cpp_BINDINGS "shiboken")
set(qt_gui_cpp_BINDINGS "${qt_gui_cpp_BINDINGS}" PARENT_SCOPE)

set(QT_INCLUDE_DIR "${Qt5Widgets_INCLUDE_DIRS}")
shiboken_generator(
libqt_gui_cpp
global.h
typesystem.xml
${PROJECT_SOURCE_DIR}/src/qt_gui_cpp_shiboken
"${qt_gui_cpp_shiboken_SRCS}"
"${qt_gui_cpp_HDRS}"
"${qt_gui_cpp_INCLUDE_PATH}"
"${CMAKE_CURRENT_BINARY_DIR}")
set(QT_INCLUDE_DIR "${Qt5Widgets_INCLUDE_DIRS}")
shiboken_generator(
libqt_gui_cpp
global.h
typesystem.xml
${PROJECT_SOURCE_DIR}/src/qt_gui_cpp_shiboken
"${qt_gui_cpp_shiboken_SRCS}"
"${qt_gui_cpp_HDRS}"
"${qt_gui_cpp_INCLUDE_PATH}"
"${CMAKE_CURRENT_BINARY_DIR}")

shiboken_include_directories(qt_gui_cpp_shiboken "${qt_gui_cpp_shiboken_QT_COMPONENTS}")
shiboken_include_directories(qt_gui_cpp_shiboken "${qt_gui_cpp_shiboken_QT_COMPONENTS}")

add_library(qt_gui_cpp_shiboken SHARED ${qt_gui_cpp_shiboken_SRCS})
target_include_directories(qt_gui_cpp_shiboken PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../include)
target_link_libraries(qt_gui_cpp_shiboken
${PROJECT_NAME}
pluginlib::pluginlib
tinyxml2::tinyxml2
)
shiboken_target_link_libraries(qt_gui_cpp_shiboken "${qt_gui_cpp_shiboken_QT_COMPONENTS}")
add_library(qt_gui_cpp_shiboken SHARED ${qt_gui_cpp_shiboken_SRCS})
target_include_directories(qt_gui_cpp_shiboken PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../include)
target_link_libraries(qt_gui_cpp_shiboken
${PROJECT_NAME}
pluginlib::pluginlib
tinyxml2::tinyxml2
)
shiboken_target_link_libraries(qt_gui_cpp_shiboken "${qt_gui_cpp_shiboken_QT_COMPONENTS}")

install(TARGETS qt_gui_cpp_shiboken
DESTINATION ${PYTHON_INSTALL_DIR}/${PROJECT_NAME})
endif()
install(TARGETS qt_gui_cpp_shiboken
DESTINATION ${PYTHON_INSTALL_DIR}/${PROJECT_NAME})
endif()
endif()
109 changes: 14 additions & 95 deletions qt_gui_cpp/src/qt_gui_cpp_sip/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
set(qt_gui_cpp_HDRS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../include/qt_gui_cpp)

set(qt_gui_cpp_sip "qt_gui_cpp.sip")
if(${QT_VERSION_MAJOR} GREATER "5")
if(${qt_gui_cpp_USE_QT_MAJOR_VERSION} GREATER "5")
set(qt_gui_cpp_sip "qt_gui_cpp_6.sip")
endif()

Expand Down Expand Up @@ -32,110 +32,29 @@ set(qt_gui_cpp_sip_DEPENDENT_FILES
${qt_gui_cpp_HDRS_DIR}/settings.hpp
)

# maintain context for different named target
set(qt_gui_cpp_sip_INCLUDE_DIRS ${qt_gui_cpp_INCLUDE_DIRS} "${CMAKE_CURRENT_SOURCE_DIR}/../../include")
set(qt_gui_cpp_sip_LIBRARY_DIRS ${qt_gui_cpp_LIBRARY_DIRS} lib)
set(qt_gui_cpp_sip_LDFLAGS_OTHER ${qt_gui_cpp_LDFLAGS_OTHER})

ament_get_recursive_properties(deps_include_dirs deps_libraries ${pluginlib_TARGETS})
list(APPEND deps_include_dirs ${TinyXML2_INCLUDE_DIRS})
list(APPEND deps_libraries ${TinyXML2_LIBRARIES})

# By default, without the settings below, find_package(Python3) will attempt
# to find the newest python version it can, and additionally will find the
# most specific version. For instance, on a system that has
# /usr/bin/python3.10, /usr/bin/python3.11, and /usr/bin/python3, it will find
# /usr/bin/python3.11, even if /usr/bin/python3 points to /usr/bin/python3.10.
# The behavior we want is to prefer the "system" installed version unless the
# user specifically tells us othewise through the Python3_EXECUTABLE hint.
# Setting CMP0094 to NEW means that the search will stop after the first
# python version is found. Setting Python3_FIND_UNVERSIONED_NAMES means that
# the search will prefer /usr/bin/python3 over /usr/bin/python3.11. And that
# latter functionality is only available in CMake 3.20 or later, so we need
# at least that version.
cmake_minimum_required(VERSION 3.20)
cmake_policy(SET CMP0094 NEW)
set(Python3_FIND_UNVERSIONED_NAMES FIRST)

find_package(Python3 REQUIRED COMPONENTS Development)

set(_qt_gui_cpp_sip_LIBRARIES
${deps_libraries}
Python3::Python
set(qt_gui_cpp_sip_LIBRARIES
${TinyXML2_LIBRARIES}
${pluginlib_TARGETS}
qt_gui_cpp
)

# sip needs libraries to have resolved paths and cannot link to cmake targets
foreach(_lib_name ${_qt_gui_cpp_sip_LIBRARIES})
if(TARGET ${_lib_name})
# Use a nifty cmake generator expression to resolve the target location
list(APPEND qt_gui_cpp_sip_LIBRARIES $<TARGET_FILE:${_lib_name}>)
else()
# This library should work as is
list(APPEND qt_gui_cpp_sip_LIBRARIES ${_lib_name})
endif()
endforeach()

find_package(python_qt_binding REQUIRED)
include(${python_qt_binding_DIR}/sip_helper.cmake)

ament_export_dependencies(pluginlib)
include_directories(${PROJECT_NAME} ${qt_gui_cpp_INCLUDE_DIRECTORIES} ${deps_include_dirs})

# The include directories used by build_sip_binding are different than the one set in include directories
set(qt_gui_cpp_sip_INCLUDE_DIRS ${qt_gui_cpp_sip_INCLUDE_DIRS} ${deps_include_dirs})

if(sip_helper_FOUND)
list(APPEND qt_gui_cpp_BINDINGS "sip")
set(qt_gui_cpp_BINDINGS "${qt_gui_cpp_BINDINGS}" PARENT_SCOPE)

if(${QT_VERSION_MAJOR} GREATER "5")
# Get all relevant Qt include dirs, to pass them on to shiboken.
get_property(QT_WIDGETS_INCLUDE_DIRS TARGET Qt${QT_VERSION_MAJOR}::Widgets PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
set(INCLUDES "")
foreach(INCLUDE_DIR ${QT_WIDGETS_INCLUDE_DIRS})
list(APPEND INCLUDES "-I${INCLUDE_DIR}")
endforeach()

# We need to include the headers for the module bindings that we use.
set(PYSIDE_ADDITIONAL_INCLUDES "")
foreach(INCLUDE_DIR ${PYSIDE_INCLUDE_DIR})
list(APPEND PYSIDE_ADDITIONAL_INCLUDES "${INCLUDE_DIR}/QtCore")
list(APPEND PYSIDE_ADDITIONAL_INCLUDES "${INCLUDE_DIR}/QtGui")
list(APPEND PYSIDE_ADDITIONAL_INCLUDES "${INCLUDE_DIR}/QtWidgets")
endforeach()
build_sip_6_binding(qt_gui_cpp_sip qt_gui_cpp.sip
SOURCE_DIR ${PROJECT_SOURCE_DIR}/src/qt_gui_cpp_sip
LIBRARY_DIR ${CMAKE_CURRENT_BINARY_DIR}
DEPENDS ${qt_gui_cpp_sip_DEPENDENT_FILES}
DEPENDENCIES qt_gui_cpp
)
else()
build_sip_binding(qt_gui_cpp_sip qt_gui_cpp.sip
SOURCE_DIR ${PROJECT_SOURCE_DIR}/src/qt_gui_cpp_sip
LIBRARY_DIR ${CMAKE_CURRENT_BINARY_DIR}
DEPENDS ${qt_gui_cpp_sip_DEPENDENT_FILES}
DEPENDENCIES qt_gui_cpp
)
endif()

if(APPLE)
set(LIBQT_GUI_CPP_SIP_SUFFIX .so)
elseif(WIN32)
set(LIBQT_GUI_CPP_SIP_SUFFIX .pyd)
else()
set(LIBQT_GUI_CPP_SIP_SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX})
endif()

if(${QT_VERSION_MAJOR} GREATER "5")
execute_process(
COMMAND ${Python3_EXECUTABLE} -c "import sysconfig as c; print(c.get_config_var('EXT_SUFFIX'), end='')"
OUTPUT_VARIABLE PYTHON_EXTENSION_MODULE_SUFFIX
ERROR_QUIET)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libqt_gui_cpp_sip${PYTHON_EXTENSION_MODULE_SUFFIX}
DESTINATION ${PYTHON_INSTALL_DIR}/${PROJECT_NAME})
else()
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libqt_gui_cpp_sip${LIBQT_GUI_CPP_SIP_SUFFIX}
DESTINATION ${PYTHON_INSTALL_DIR}/${PROJECT_NAME})
endif()
build_sip_binding(qt_gui_cpp_sip ${qt_gui_cpp_sip}
SOURCE_DIR ${PROJECT_SOURCE_DIR}/src/qt_gui_cpp_sip
LIBRARY_DIR ${CMAKE_CURRENT_BINARY_DIR}
DEPENDS ${qt_gui_cpp_sip_DEPENDENT_FILES}
DEPENDENCIES qt_gui_cpp ${deps_libraries}
)
# build_sip_binding prefixes the target with "lib"
install(TARGETS libqt_gui_cpp_sip
DESTINATION "${PYTHON_INSTALL_DIR}/${PROJECT_NAME}"
)
endif()