From d502470e743ee5288e29e98c824014dc2bb7ecaf Mon Sep 17 00:00:00 2001 From: Alex Shvartzkop Date: Sat, 1 Jun 2024 04:17:41 +0300 Subject: [PATCH 1/5] wxQt-specific ifdefs. --- common/dialog_shim.cpp | 5 +++-- include/gal/opengl/gl_utils.h | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/common/dialog_shim.cpp b/common/dialog_shim.cpp index d45f1e4844..50f4178b5a 100644 --- a/common/dialog_shim.cpp +++ b/common/dialog_shim.cpp @@ -511,10 +511,11 @@ int DIALOG_SHIM::ShowQuasiModal() wxWindow* parent = GetParentForModalDialog( GetParent(), GetWindowStyle() ); wxASSERT_MSG( !m_qmodal_parent_disabler, wxT( "Caller using ShowQuasiModal() twice on same " - "window?" ) ); - + "window?" ) ); +#ifndef __WXQT__ // quasi-modal: disable only my "optimal" parent m_qmodal_parent_disabler = new WDO_ENABLE_DISABLE( parent ); +#endif // Apple in its infinite wisdom will raise a disabled window before even passing // us the event, so we have no way to stop it. Instead, we must set an order on diff --git a/include/gal/opengl/gl_utils.h b/include/gal/opengl/gl_utils.h index 2d1f3f675c..4d2153e566 100644 --- a/include/gal/opengl/gl_utils.h +++ b/include/gal/opengl/gl_utils.h @@ -109,7 +109,7 @@ public: } } -#elif defined( _WIN32 ) +#elif defined( _WIN32 ) and not defined( __WXQT__ ) const GLubyte* vendor = glGetString( GL_VENDOR ); //const GLubyte* renderer = glGetString( GL_RENDERER ); From f192c5b17464cae83cfcb012d272a7687f782074 Mon Sep 17 00:00:00 2001 From: Alex Shvartzkop Date: Sat, 1 Jun 2024 05:11:49 +0300 Subject: [PATCH 2/5] MSVC workaround to prevent errors when linking kicommon with wx 3.3. --- CMakeLists.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index e5560f86a4..e6c005ea24 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1077,6 +1077,14 @@ else() message( FATAL_ERROR "Unable to detect wxWidgets port") endif() +if( MSVC AND NOT ${wxWidgets_VERSION_STRING} VERSION_LESS 3.3 ) + # wx 3.3 exports std::vector methods from the dll, causing multiple definition + # errors when linking kicommon. /FORCE:MULTIPLE works around this issue. + foreach( type EXE SHARED MODULE ) + string( APPEND CMAKE_${type}_LINKER_FLAGS " /FORCE:MULTIPLE" ) + endforeach() +endif() + if( NOT MSVC ) if( ${wxWidgets_VERSION_STRING} VERSION_LESS 3.2 ) message( FATAL_ERROR "wxWidgets 3.2.0 or greater is required" ) From 2b957e520cd29e57f47e4d63df500040d956d6d9 Mon Sep 17 00:00:00 2001 From: Alex Shvartzkop Date: Sat, 1 Jun 2024 10:47:43 +0300 Subject: [PATCH 3/5] Support building with wxQT wxWidgets port (experimental). --- libs/kiplatform/CMakeLists.txt | 21 +++ libs/kiplatform/port/wxqt/app.cpp | 131 ++++++++++++++++ libs/kiplatform/port/wxqt/environment.cpp | 93 +++++++++++ libs/kiplatform/port/wxqt/qtconv.h | 33 ++++ libs/kiplatform/port/wxqt/ui.cpp | 180 ++++++++++++++++++++++ 5 files changed, 458 insertions(+) create mode 100644 libs/kiplatform/port/wxqt/app.cpp create mode 100644 libs/kiplatform/port/wxqt/environment.cpp create mode 100644 libs/kiplatform/port/wxqt/qtconv.h create mode 100644 libs/kiplatform/port/wxqt/ui.cpp diff --git a/libs/kiplatform/CMakeLists.txt b/libs/kiplatform/CMakeLists.txt index 62a3ea6e87..140769d280 100644 --- a/libs/kiplatform/CMakeLists.txt +++ b/libs/kiplatform/CMakeLists.txt @@ -38,6 +38,27 @@ elseif( KICAD_WX_PORT STREQUAL gtk ) message( STATUS "Configuring KiCad not to hide any GTK error messages" ) string( APPEND PLATFORM_COMPILE_DEFS "-DKICAD_SHOW_GTK_MESSAGES" ) endif() + +elseif( KICAD_WX_PORT STREQUAL qt ) + set( PLATFORM_SRCS + port/wxqt/ui.cpp + ) + + set( QT_COMPONENTS Core Widgets Gui ) + + find_package( Qt5 REQUIRED COMPONENTS ${QT_COMPONENTS} ) + set( QT_MAJOR_VERSION 5 ) + + foreach(QT_COMPONENT ${QT_COMPONENTS}) + list(APPEND QT_INC_DIRS ${Qt${QT_MAJOR_VERSION}${QT_COMPONENT}_INCLUDE_DIRS}) + list(APPEND PLATFORM_LIBS ${Qt${QT_MAJOR_VERSION}${QT_COMPONENT}_LIBRARIES}) + list(APPEND PLATFORM_COMPILE_DEFS ${Qt${QT_MAJOR_VERSION}${QT_COMPONENT}_COMPILE_DEFINITIONS}) + endforeach() + + include_directories( SYSTEM ${QT_INC_DIRS} ) + + message( STATUS "Using Qt${QT_MAJOR_VERSION} platform libraries ${PLATFORM_LIBS}" ) + endif() diff --git a/libs/kiplatform/port/wxqt/app.cpp b/libs/kiplatform/port/wxqt/app.cpp new file mode 100644 index 0000000000..8056e354cf --- /dev/null +++ b/libs/kiplatform/port/wxqt/app.cpp @@ -0,0 +1,131 @@ +/* +* This program source code file is part of KiCad, a free EDA CAD application. +* +* Copyright (C) 2020 Mark Roszko +* Copyright (C) 2020-2024 KiCad Developers, see AUTHORS.txt for contributors. +* +* This program is free software: you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation, either version 3 of the License, or (at your +* option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License along +* with this program. If not, see . +*/ + +#include + +#include +#include + +#ifdef _WIN32 +#include +#include +#include +#include +#include +#include +#endif + + +bool KIPLATFORM::APP::Init() +{ + AttachConsole( true ); + return true; +} + + +bool KIPLATFORM::APP::AttachConsole( bool aTryAlloc ) +{ +#ifdef _WIN32 + if( ::AttachConsole( ATTACH_PARENT_PROCESS ) || ( aTryAlloc && ::AllocConsole() ) ) + { + #if !defined( __MINGW32__ ) // These redirections create problems on mingw: + // Nothing is printed to the console + + if( ::GetStdHandle( STD_INPUT_HANDLE ) != INVALID_HANDLE_VALUE ) + { + freopen( "CONIN$", "r", stdin ); + setvbuf( stdin, NULL, _IONBF, 0 ); + } + + if( ::GetStdHandle( STD_OUTPUT_HANDLE ) != INVALID_HANDLE_VALUE ) + { + freopen( "CONOUT$", "w", stdout ); + setvbuf( stdout, NULL, _IONBF, 0 ); + } + + if( ::GetStdHandle( STD_ERROR_HANDLE ) != INVALID_HANDLE_VALUE ) + { + freopen( "CONOUT$", "w", stderr ); + setvbuf( stderr, NULL, _IONBF, 0 ); + } + #endif + + std::ios::sync_with_stdio( true ); + + std::wcout.clear(); + std::cout.clear(); + std::wcerr.clear(); + std::cerr.clear(); + std::wcin.clear(); + std::cin.clear(); + + return true; + } +#endif + + return false; +} + + +bool KIPLATFORM::APP::IsOperatingSystemUnsupported() +{ + // Not implemented on this platform + return false; +} + + +bool KIPLATFORM::APP::RegisterApplicationRestart( const wxString& aCommandLine ) +{ + // Not implemented on this platform + return true; +} + + +bool KIPLATFORM::APP::UnregisterApplicationRestart() +{ + // Not implemented on this platform + return true; +} + + +bool KIPLATFORM::APP::SupportsShutdownBlockReason() +{ + return false; +} + + +void KIPLATFORM::APP::RemoveShutdownBlockReason( wxWindow* aWindow ) +{ +} + + +void KIPLATFORM::APP::SetShutdownBlockReason( wxWindow* aWindow, const wxString& aReason ) +{ +} + + +void KIPLATFORM::APP::ForceTimerMessagesToBeCreatedIfNecessary() +{ +} + + +void KIPLATFORM::APP::AddDynamicLibrarySearchPath( const wxString& aPath ) +{ +} diff --git a/libs/kiplatform/port/wxqt/environment.cpp b/libs/kiplatform/port/wxqt/environment.cpp new file mode 100644 index 0000000000..cf688d397c --- /dev/null +++ b/libs/kiplatform/port/wxqt/environment.cpp @@ -0,0 +1,93 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include + +#include +#include + +#include "qtconv.h" +#include +#include +#include + + +void KIPLATFORM::ENV::Init() +{ +} + + +bool KIPLATFORM::ENV::MoveToTrash( const wxString& aPath, wxString& aError ) +{ + return QFile::moveToTrash( QString( wxString( aPath.fn_str() ) ) ); +} + + +bool KIPLATFORM::ENV::IsNetworkPath( const wxString& aPath ) +{ + // placeholder, we "nerf" behavior if its a network path so return false by default + return false; +} + + +wxString KIPLATFORM::ENV::GetDocumentsPath() +{ + return wxQtConvertString( + QStandardPaths::writableLocation( QStandardPaths::DocumentsLocation ) ); +} + + +wxString KIPLATFORM::ENV::GetUserConfigPath() +{ + return wxQtConvertString( + QStandardPaths::writableLocation( QStandardPaths::AppConfigLocation ) ); +} + + +wxString KIPLATFORM::ENV::GetUserDataPath() +{ + return wxQtConvertString( + QStandardPaths::writableLocation( QStandardPaths::GenericDataLocation ) ); +} + + +wxString KIPLATFORM::ENV::GetUserLocalDataPath() +{ + return wxQtConvertString( + QStandardPaths::writableLocation( QStandardPaths::GenericDataLocation ) ); +} + + +wxString KIPLATFORM::ENV::GetUserCachePath() +{ + return wxQtConvertString( + QStandardPaths::writableLocation( QStandardPaths::CacheLocation ) ); +} + + +bool KIPLATFORM::ENV::GetSystemProxyConfig( const wxString& aURL, PROXY_CONFIG& aCfg ) +{ + return false; +} + + +bool KIPLATFORM::ENV::VerifyFileSignature( const wxString& aPath ) +{ + return true; +} \ No newline at end of file diff --git a/libs/kiplatform/port/wxqt/qtconv.h b/libs/kiplatform/port/wxqt/qtconv.h new file mode 100644 index 0000000000..90852ce991 --- /dev/null +++ b/libs/kiplatform/port/wxqt/qtconv.h @@ -0,0 +1,33 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include +#include + + +inline wxString wxQtConvertString( const QString& str ) +{ + return wxString( str.toUtf8().data(), wxConvUTF8 ); +} + + +inline QString wxQtConvertString( const wxString& str ) +{ + return QString( str.utf8_str() ); +} \ No newline at end of file diff --git a/libs/kiplatform/port/wxqt/ui.cpp b/libs/kiplatform/port/wxqt/ui.cpp new file mode 100644 index 0000000000..17cbdec587 --- /dev/null +++ b/libs/kiplatform/port/wxqt/ui.cpp @@ -0,0 +1,180 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2020 Ian McInerney + * Copyright (C) 2020-2024 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include + + +bool KIPLATFORM::UI::IsDarkTheme() +{ + wxColour bg = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ); + + // Weighted W3C formula + double brightness = ( bg.Red() / 255.0 ) * 0.299 + + ( bg.Green() / 255.0 ) * 0.587 + + ( bg.Blue() / 255.0 ) * 0.117; + + return brightness < 0.5; +} + + +wxColour KIPLATFORM::UI::GetDialogBGColour() +{ + return wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ); +} + + +void KIPLATFORM::UI::ForceFocus( wxWindow* aWindow ) +{ + aWindow->SetFocus(); +} + + +bool KIPLATFORM::UI::IsWindowActive( wxWindow* aWindow ) +{ + if( !aWindow ) + return false; + + QWidget* widget = aWindow->GetHandle(); + + if( !widget ) + return false; + + return widget->isActiveWindow(); +} + + +void KIPLATFORM::UI::ReparentQuasiModal( wxNonOwnedWindow* aWindow ) +{ + // Not needed on this platform +} + + +void KIPLATFORM::UI::FixupCancelButtonCmdKeyCollision( wxWindow *aWindow ) +{ + // Not needed on this platform +} + + +bool KIPLATFORM::UI::IsStockCursorOk( wxStockCursor aCursor ) +{ + switch( aCursor ) + { + case wxCURSOR_BULLSEYE: + case wxCURSOR_HAND: + case wxCURSOR_ARROW: + case wxCURSOR_BLANK: + return true; + default: + return false; + } +} + + +void KIPLATFORM::UI::LargeChoiceBoxHack( wxChoice* aChoice ) +{ + +} + + +void KIPLATFORM::UI::EllipsizeChoiceBox( wxChoice* aChoice ) +{ +} + + +double KIPLATFORM::UI::GetPixelScaleFactor( const wxWindow* aWindow ) +{ + return aWindow->GetContentScaleFactor(); +} + + +double KIPLATFORM::UI::GetContentScaleFactor( const wxWindow* aWindow ) +{ + return aWindow->GetDPIScaleFactor(); +} + + +wxSize KIPLATFORM::UI::GetUnobscuredSize( const wxWindow* aWindow ) +{ + return wxSize( aWindow->GetSize().GetX() - wxSystemSettings::GetMetric( wxSYS_VSCROLL_X ), + aWindow->GetSize().GetY() - wxSystemSettings::GetMetric( wxSYS_HSCROLL_Y ) ); +} + + +void KIPLATFORM::UI::SetOverlayScrolling( const wxWindow* aWindow, bool overlay ) +{ +} + + +bool KIPLATFORM::UI::AllowIconsInMenus() +{ + return true; +} + + +bool KIPLATFORM::UI::WarpPointer( wxWindow* aWindow, int aX, int aY ) +{ + aWindow->WarpPointer( aX, aY ); + return true; +} + + +void KIPLATFORM::UI::ImmControl( wxWindow* aWindow, bool aEnable ) +{ + // Not implemented +} + + +void KIPLATFORM::UI::ImeNotifyCancelComposition( wxWindow* aWindow ) +{ + // Not implemented +} + + +bool KIPLATFORM::UI::InfiniteDragPrepareWindow( wxWindow* aWindow ) +{ + return true; +} + + +void KIPLATFORM::UI::InfiniteDragReleaseWindow() +{ + // Not needed +} + + +void KIPLATFORM::UI::SetFloatLevel( wxWindow* aWindow ) +{ + // Not needed +} + + +wxPoint KIPLATFORM::UI::GetMousePosition() +{ + return wxGetMousePosition(); +} From 2efc256a75240a37b096b125b8d1e182f8de5e95 Mon Sep 17 00:00:00 2001 From: Alex Shvartzkop Date: Sat, 1 Jun 2024 11:26:36 +0300 Subject: [PATCH 4/5] Don't force gtk3 on Unix-based systems. --- CMakeLists.txt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e6c005ea24..6300f52d65 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1035,10 +1035,7 @@ if( WXWIDGETS_REQUESTED_TOOLKIT message( WARNING "wxWidgets and wxPython must be based on the same toolkit.\n" "It will be fixed automatically if you skip the '--toolkit=xxx' " "wxWidgets_CONFIG_OPTIONS parameter.") -elseif( UNIX AND NOT APPLE ) - # Force the use of GTK3 on Linux - set( wxWidgets_CONFIG_OPTIONS ${wxWidgets_CONFIG_OPTIONS} "--toolkit=gtk3" ) -else() +elseif( WXPYTHON_TOOLKIT ) # Use the same toolkit as wxPython otherwise there will be a symbol conflict set( wxWidgets_CONFIG_OPTIONS ${wxWidgets_CONFIG_OPTIONS} "--toolkit=${WXPYTHON_TOOLKIT}" ) endif() From 96fb82e7697074c8fcdd3a4ae49e3785e5e0182c Mon Sep 17 00:00:00 2001 From: Alex Shvartzkop Date: Fri, 21 Jun 2024 21:30:51 +0300 Subject: [PATCH 5/5] Allow using custom getProcAddress for glew; Render OpenGL in paint event. Fixes OpenGL rendering on Linux. --- 3d-viewer/3d_canvas/eda_3d_canvas.cpp | 2 +- .../3d_model_viewer/eda_3d_model_viewer.cpp | 2 +- CMakeLists.txt | 97 ++++++++++--------- common/draw_panel_gal.cpp | 8 +- common/gal/opengl/opengl_compositor.cpp | 11 ++- common/gal/opengl/opengl_gal.cpp | 9 +- include/gal/opengl/gl_utils.h | 4 +- include/gal/opengl/kiglew.h | 29 +++++- libs/kiplatform/CMakeLists.txt | 1 + .../kiplatform/include/kiplatform/opengl_qt.h | 38 ++++++++ libs/kiplatform/port/wxqt/opengl_qt.cpp | 48 +++++++++ thirdparty/glew/CMakeLists.txt | 11 ++- thirdparty/glew/include/GL/glew.h | 5 + thirdparty/glew/src/glew.c | 24 +++-- 14 files changed, 218 insertions(+), 71 deletions(-) create mode 100644 libs/kiplatform/include/kiplatform/opengl_qt.h create mode 100644 libs/kiplatform/port/wxqt/opengl_qt.cpp diff --git a/3d-viewer/3d_canvas/eda_3d_canvas.cpp b/3d-viewer/3d_canvas/eda_3d_canvas.cpp index 2a2f53fa5a..578c46badb 100644 --- a/3d-viewer/3d_canvas/eda_3d_canvas.cpp +++ b/3d-viewer/3d_canvas/eda_3d_canvas.cpp @@ -223,7 +223,7 @@ bool EDA_3D_CANVAS::initializeOpenGL() { wxLogTrace( m_logTrace, wxT( "EDA_3D_CANVAS::initializeOpenGL" ) ); - const GLenum err = glewInit(); + const GLenum err = kiglewInit(); if( GLEW_OK != err ) { diff --git a/3d-viewer/3d_model_viewer/eda_3d_model_viewer.cpp b/3d-viewer/3d_model_viewer/eda_3d_model_viewer.cpp index fc1b7eaf72..a55a3c4a07 100644 --- a/3d-viewer/3d_model_viewer/eda_3d_model_viewer.cpp +++ b/3d-viewer/3d_model_viewer/eda_3d_model_viewer.cpp @@ -182,7 +182,7 @@ void EDA_3D_MODEL_VIEWER::Clear3DModel() void EDA_3D_MODEL_VIEWER::ogl_initialize() { - const GLenum err = glewInit(); + const GLenum err = kiglewInit(); if( GLEW_OK != err ) { diff --git a/CMakeLists.txt b/CMakeLists.txt index 6300f52d65..21d44cfec7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -121,10 +121,9 @@ cmake_dependent_option( KICAD_USE_EGL OFF "UNIX_NOT_APPLE" OFF) -cmake_dependent_option( KICAD_USE_BUNDLED_GLEW - "Use the bundled version of GLEW - only available when KICAD_USE_EGL is set" - ON "KICAD_USE_EGL" - OFF ) +option( KICAD_USE_BUNDLED_GLEW + "Use the bundled version of GLEW" + ${KICAD_USE_EGL} ) cmake_dependent_option( KICAD_WAYLAND "Support Wayland features" @@ -760,50 +759,6 @@ if( KICAD_BUILD_I18N ) find_package( Gettext REQUIRED ) endif() -# -# Find OpenGL library, required -# -if( KICAD_USE_EGL ) - find_package( OpenGL REQUIRED COMPONENTS OpenGL EGL ) -else() - set( OpenGL_GL_PREFERENCE "LEGACY" ) # CMake 3.11+ setting; see 'cmake --help-policy CMP0072' - find_package( OpenGL REQUIRED ) -endif() - -# -# Find GLEW library, required -# -# The EGL canvas on GTK requires the use of a GLEW version compiled with an EGL flag. -# The one built in the thirdparty directory has the flag for EGL set, so we use it unless told -# otherwise. Then we search for the system GLEW version and use that instead. -# -if( KICAD_USE_EGL AND KICAD_USE_BUNDLED_GLEW AND UNIX AND NOT APPLE ) - if( OpenGL_EGL_FOUND ) - message( STATUS "Found OpenGL EGL library: ${OPENGL_egl_LIBRARY}" ) - else() - message( FATAL_ERROR "OpenGL EGL library not found" ) - endif() - - # Add the custom GLEW target - add_subdirectory( thirdparty/glew ) - - # Set the standard package variables to point to our custom target to mimic the system version. - set( GLEW_LIBRARIES glew ) - set( GLEW_FOUND TRUE ) - include_directories( SYSTEM $ ) -else() - find_package( GLEW REQUIRED ) - check_find_package_result( GLEW_FOUND "GLEW" ) - include_directories( SYSTEM ${GLEW_INCLUDE_DIR} ) -endif() - -# -# Find GLM library, required -# -find_package( GLM 0.9.8 REQUIRED ) -add_compile_definitions( GLM_FORCE_CTOR_INIT ) -include_directories( SYSTEM ${GLM_INCLUDE_DIR} ) - # # Find zlib library, required # @@ -1098,6 +1053,52 @@ if( MINGW ) endif() endif() +# +# Find OpenGL library, required +# +if( KICAD_USE_EGL ) + find_package( OpenGL REQUIRED COMPONENTS OpenGL EGL ) +else() + set( OpenGL_GL_PREFERENCE "LEGACY" ) # CMake 3.11+ setting; see 'cmake --help-policy CMP0072' + find_package( OpenGL REQUIRED ) +endif() + +# +# Find GLEW library, required +# +# The EGL canvas on GTK requires the use of a GLEW version compiled with an EGL flag. +# The one built in the thirdparty directory has the flag for EGL set, so we use it unless told +# otherwise. Then we search for the system GLEW version and use that instead. +# +if( KICAD_USE_EGL ) + if( OpenGL_EGL_FOUND ) + message( STATUS "Found OpenGL EGL library: ${OPENGL_egl_LIBRARY}" ) + else() + message( FATAL_ERROR "OpenGL EGL library not found" ) + endif() +endif() + +if( KICAD_USE_BUNDLED_GLEW AND UNIX AND NOT APPLE ) + # Add the custom GLEW target + add_subdirectory( thirdparty/glew ) + + # Set the standard package variables to point to our custom target to mimic the system version. + set( GLEW_LIBRARIES glew ) + set( GLEW_FOUND TRUE ) + include_directories( SYSTEM $ ) +else() + find_package( GLEW REQUIRED ) + check_find_package_result( GLEW_FOUND "GLEW" ) + include_directories( SYSTEM ${GLEW_INCLUDE_DIR} ) +endif() + +# +# Find GLM library, required +# +find_package( GLM 0.9.8 REQUIRED ) +add_compile_definitions( GLM_FORCE_CTOR_INIT ) +include_directories( SYSTEM ${GLM_INCLUDE_DIR} ) + if( APPLE ) # Remove app bundles in ${KICAD_BIN} before installing anything new. # Must be defined before all includes so that it is executed first. diff --git a/common/draw_panel_gal.cpp b/common/draw_panel_gal.cpp index 538eb21475..f638fdba8f 100644 --- a/common/draw_panel_gal.cpp +++ b/common/draw_panel_gal.cpp @@ -200,6 +200,9 @@ void EDA_DRAW_PANEL_GAL::onPaint( wxPaintEvent& WXUNUSED( aEvent ) ) bool EDA_DRAW_PANEL_GAL::DoRePaint() { + if( m_gal->IsContextLocked() ) + return false; + if( !m_refreshMutex.try_lock() ) return false; @@ -389,8 +392,7 @@ void EDA_DRAW_PANEL_GAL::RequestRefresh() void EDA_DRAW_PANEL_GAL::Refresh( bool aEraseBackground, const wxRect* aRect ) { - if( !DoRePaint() ) - RequestRefresh(); + wxScrolledCanvas::Refresh( aEraseBackground, aRect ); } @@ -415,7 +417,7 @@ void EDA_DRAW_PANEL_GAL::ForceRefresh() } } - DoRePaint(); + Refresh(); } diff --git a/common/gal/opengl/opengl_compositor.cpp b/common/gal/opengl/opengl_compositor.cpp index 3db5168ccc..fa31bf97b9 100644 --- a/common/gal/opengl/opengl_compositor.cpp +++ b/common/gal/opengl/opengl_compositor.cpp @@ -384,7 +384,16 @@ void OPENGL_COMPOSITOR::bindFb( unsigned int aFb ) if( m_curFbo != aFb ) { - glBindFramebufferEXT( GL_FRAMEBUFFER, aFb ); + unsigned int actualBuffer = aFb; + +#ifdef __WXQT__ + // Qt needs to draw on a separate framebuffer first + if( aFb == DIRECT_RENDERING ) + actualBuffer = QtOpenGLGetOutputFBO(); +#endif + + glBindFramebufferEXT( GL_FRAMEBUFFER, actualBuffer ); + checkGlError( "switching framebuffer", __FILE__, __LINE__ ); m_curFbo = aFb; } diff --git a/common/gal/opengl/opengl_gal.cpp b/common/gal/opengl/opengl_gal.cpp index c982958056..4aa5b0b2d4 100644 --- a/common/gal/opengl/opengl_gal.cpp +++ b/common/gal/opengl/opengl_gal.cpp @@ -499,9 +499,9 @@ wxString OPENGL_GAL::CheckFeatures( GAL_DISPLAY_OPTIONS& aOptions ) void OPENGL_GAL::PostPaint( wxPaintEvent& aEvent ) { - // posts an event to m_paint_listener to ask for redraw the canvas. + // Repaint it immediately via m_paintListener. if( m_paintListener ) - wxPostEvent( m_paintListener, aEvent ); + m_paintListener->ProcessEvent( aEvent ); } @@ -2687,7 +2687,8 @@ void OPENGL_GAL::init() // Check correct initialization from the constructor if( m_tesselator == nullptr ) throw std::runtime_error( "Could not create the tesselator" ); - GLenum err = glewInit(); + + GLenum err = kiglewInit(); #ifdef KICAD_USE_EGL // TODO: better way to check when EGL is ready (init fails at "getString(GL_VERSION)") @@ -2697,7 +2698,7 @@ void OPENGL_GAL::init() break; std::this_thread::sleep_for( std::chrono::milliseconds( 250 ) ); - err = glewInit(); + err = kiglewInit(); } #endif // KICAD_USE_EGL diff --git a/include/gal/opengl/gl_utils.h b/include/gal/opengl/gl_utils.h index 4d2153e566..dc097c7455 100644 --- a/include/gal/opengl/gl_utils.h +++ b/include/gal/opengl/gl_utils.h @@ -48,7 +48,7 @@ public: */ static int SetSwapInterval( int aVal ) { -#if defined( __linux__ ) && !defined( KICAD_USE_EGL ) +#if defined( __linux__ ) && !defined( KICAD_USE_EGL ) && !defined( __WXQT__ ) if( Display* dpy = glXGetCurrentDisplay() ) { @@ -109,7 +109,7 @@ public: } } -#elif defined( _WIN32 ) and not defined( __WXQT__ ) +#elif defined( _WIN32 ) and !defined( __WXQT__ ) const GLubyte* vendor = glGetString( GL_VENDOR ); //const GLubyte* renderer = glGetString( GL_RENDERER ); diff --git a/include/gal/opengl/kiglew.h b/include/gal/opengl/kiglew.h index 7eaf8fccc3..e343368e4d 100644 --- a/include/gal/opengl/kiglew.h +++ b/include/gal/opengl/kiglew.h @@ -31,12 +31,16 @@ // Pull in the configuration options for wxWidgets #include +#ifdef __WXQT__ +#include +#endif + // Apple, in their infinite wisdom, has decided to mark OpenGL as deprecated. // Luckily we can silence warnings about its deprecation. This is needed on the GLEW // includes since they transitively include the OpenGL headers. #define GL_SILENCE_DEPRECATION 1 -#if defined( __unix__ ) and not defined( __APPLE__ ) +#if defined( __unix__ ) and not defined( __APPLE__ ) and not defined( __WXQT__ ) #ifdef KICAD_USE_EGL @@ -54,6 +58,11 @@ #else // wxWidgets wasn't compiled with the EGL canvas, so use the X11 GLEW #include + + // Resolve X.h conflict with wx 3.3 + #ifdef Success + #undef Success + #endif #endif #endif // KICAD_USE_EGL @@ -63,12 +72,24 @@ // Non-GTK platforms only need the normal GLEW include #include -#endif // defined( __unix__ ) and not defined( __APPLE__ ) +#endif // defined( __unix__ ) and not defined( __APPLE__ ) and not defined( __WXQT__ ) -#ifdef _WIN32 +#if defined( _WIN32 ) and not defined( __WXQT__ ) #include -#endif // _WIN32 +#endif // defined( _WIN32 ) and not defined( __WXQT__ ) + + +inline GLenum kiglewInit() +{ +#ifdef __WXQT__ + GLenum err = glewInit( &QtOpenGLGetProcAddress ); +#else + GLenum err = glewInit(); +#endif + return err; +} + #endif // KIGLEW_H_ diff --git a/libs/kiplatform/CMakeLists.txt b/libs/kiplatform/CMakeLists.txt index 140769d280..dfc72ee6c6 100644 --- a/libs/kiplatform/CMakeLists.txt +++ b/libs/kiplatform/CMakeLists.txt @@ -42,6 +42,7 @@ elseif( KICAD_WX_PORT STREQUAL gtk ) elseif( KICAD_WX_PORT STREQUAL qt ) set( PLATFORM_SRCS port/wxqt/ui.cpp + port/wxqt/opengl_qt.cpp ) set( QT_COMPONENTS Core Widgets Gui ) diff --git a/libs/kiplatform/include/kiplatform/opengl_qt.h b/libs/kiplatform/include/kiplatform/opengl_qt.h new file mode 100644 index 0000000000..54a977dce8 --- /dev/null +++ b/libs/kiplatform/include/kiplatform/opengl_qt.h @@ -0,0 +1,38 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2024 Alex Shvartzkop + * Copyright (C) 2024 Kicad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __OPENGL_QT_KICAD +#define __OPENGL_QT_KICAD + +#include + + +// A proxy function for Qt getProcAddress of current context +void* QtOpenGLGetProcAddress( const char* aName ); + +// A proxy function for Qt defaultFramebufferObject of current context +unsigned int QtOpenGLGetOutputFBO(); + + +#endif // __OPENGL_QT_KICAD \ No newline at end of file diff --git a/libs/kiplatform/port/wxqt/opengl_qt.cpp b/libs/kiplatform/port/wxqt/opengl_qt.cpp new file mode 100644 index 0000000000..9cbfafe849 --- /dev/null +++ b/libs/kiplatform/port/wxqt/opengl_qt.cpp @@ -0,0 +1,48 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2024 Alex Shvartzkop + * Copyright (C) 2024 Kicad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include + + +void* QtOpenGLGetProcAddress( const char* aName ) +{ + QOpenGLContext* ctx = QOpenGLContext::currentContext(); + + if( !ctx ) + return nullptr; + + return (void*) ctx->getProcAddress( aName ); +} + + +unsigned int QtOpenGLGetOutputFBO() +{ + QOpenGLContext* ctx = QOpenGLContext::currentContext(); + + if( !ctx ) + return 0; + + return ctx->defaultFramebufferObject(); +} \ No newline at end of file diff --git a/thirdparty/glew/CMakeLists.txt b/thirdparty/glew/CMakeLists.txt index 32dd3be9ca..48200d7fcc 100644 --- a/thirdparty/glew/CMakeLists.txt +++ b/thirdparty/glew/CMakeLists.txt @@ -8,9 +8,18 @@ target_include_directories( glew PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include" ) # Definitions for compiling GLEW staticly for EGL (extracted from the main GLEW CMakeLists.txt file) add_compile_definitions( GLEW_STATIC ) -add_compile_definitions( GLEW_EGL ) add_compile_definitions( GLEW_NO_GLU ) +if( KICAD_USE_EGL ) + add_compile_definitions( GLEW_EGL ) + target_compile_definitions( glew INTERFACE GLEW_EGL ) +endif() + +if( KICAD_WX_PORT STREQUAL "qt" ) + add_compile_definitions( GLEW_RAW_PTR ) + target_compile_definitions( glew INTERFACE GLEW_RAW_PTR ) +endif() + target_sources( glew PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/glew.c ) diff --git a/thirdparty/glew/include/GL/glew.h b/thirdparty/glew/include/GL/glew.h index 64e92d1a07..ca001eb55e 100644 --- a/thirdparty/glew/include/GL/glew.h +++ b/thirdparty/glew/include/GL/glew.h @@ -26512,7 +26512,12 @@ VERSION_MICRO 0 */ /* API */ +#ifdef GLEW_RAW_PTR +GLEWAPI GLenum GLEWAPIENTRY glewInit (void *(* getProcAddressFn)(const char *)); +#else GLEWAPI GLenum GLEWAPIENTRY glewInit (void); +#endif + GLEWAPI GLboolean GLEWAPIENTRY glewIsSupported (const char *name); #define glewIsExtensionSupported(x) glewIsSupported(x) diff --git a/thirdparty/glew/src/glew.c b/thirdparty/glew/src/glew.c index cdf17c162e..55d6bc6fe5 100644 --- a/thirdparty/glew/src/glew.c +++ b/thirdparty/glew/src/glew.c @@ -36,6 +36,7 @@ # include GLEW_INCLUDE #endif +#ifndef GLEW_RAW_PTR #if defined(GLEW_OSMESA) # define GLAPI extern # include @@ -54,10 +55,13 @@ #elif !defined(__ANDROID__) && !defined(__native_client__) && !defined(__HAIKU__) && (!defined(__APPLE__) || defined(GLEW_APPLE_GLX)) # include #endif +#endif #include /* For size_t */ -#if defined(GLEW_EGL) +#if defined(GLEW_RAW_PTR) +static void *(*glew_GetProcAddressPtr)(const unsigned char *procName); +#elif defined(GLEW_EGL) #elif defined(GLEW_REGAL) /* In GLEW_REGAL mode we call direcly into the linked @@ -158,7 +162,9 @@ void* NSGLGetProcAddress (const GLubyte *name) /* * Define glewGetProcAddress. */ -#if defined(GLEW_REGAL) +#if defined(GLEW_RAW_PTR) +# define glewGetProcAddress(name) (*glew_GetProcAddressPtr)(name) +#elif defined(GLEW_REGAL) # define glewGetProcAddress(name) regalGetProcAddress((const GLchar *)name) #elif defined(GLEW_OSMESA) # define glewGetProcAddress(name) OSMesaGetProcAddress((const char *)name) @@ -22137,7 +22143,7 @@ GLenum GLEWAPIENTRY wglewInit () return GLEW_OK; } -#elif !defined(__ANDROID__) && !defined(__native_client__) && !defined(__HAIKU__) && (!defined(__APPLE__) || defined(GLEW_APPLE_GLX)) +#elif !defined(GLEW_RAW_PTR) && !defined(__ANDROID__) && !defined(__native_client__) && !defined(__HAIKU__) && (!defined(__APPLE__) || defined(GLEW_APPLE_GLX)) PFNGLXGETCURRENTDISPLAYPROC __glewXGetCurrentDisplay = NULL; @@ -23226,7 +23232,7 @@ GLenum glxewInit () return GLEW_OK; } -#endif /* !defined(__ANDROID__) && !defined(__native_client__) && !defined(__HAIKU__) && (!defined(__APPLE__) || defined(GLEW_APPLE_GLX)) */ +#endif /* !defined(GLEW_RAW_PTR) && !defined(__ANDROID__) && !defined(__native_client__) && !defined(__HAIKU__) && (!defined(__APPLE__) || defined(GLEW_APPLE_GLX)) */ /* ------------------------------------------------------------------------ */ @@ -23262,8 +23268,14 @@ const GLubyte * GLEWAPIENTRY glewGetString (GLenum name) GLboolean glewExperimental = GL_FALSE; +#ifdef GLEW_RAW_PTR +GLenum GLEWAPIENTRY glewInit (void *(* getProcAddressFn)(const char *)) +{ + glew_GetProcAddressPtr = (void* (*) (const unsigned char*) ) getProcAddressFn; +#else GLenum GLEWAPIENTRY glewInit (void) { +#endif GLenum r; #if defined(GLEW_EGL) PFNEGLGETCURRENTDISPLAYPROC getCurrentDisplay = NULL; @@ -23273,7 +23285,7 @@ GLenum GLEWAPIENTRY glewInit (void) #if defined(GLEW_EGL) getCurrentDisplay = (PFNEGLGETCURRENTDISPLAYPROC) glewGetProcAddress("eglGetCurrentDisplay"); return eglewInit(getCurrentDisplay()); -#elif defined(GLEW_OSMESA) || defined(__ANDROID__) || defined(__native_client__) || defined(__HAIKU__) +#elif defined(GLEW_RAW_PTR) || defined(GLEW_OSMESA) || defined(__ANDROID__) || defined(__native_client__) || defined(__HAIKU__) return r; #elif defined(_WIN32) return wglewInit(); @@ -30432,7 +30444,7 @@ GLboolean GLEWAPIENTRY wglewIsSupported (const char* name) return ret; } -#elif !defined(GLEW_OSMESA) && !defined(GLEW_EGL) && !defined(__ANDROID__) && !defined(__native_client__) && !defined(__HAIKU__) && !defined(__APPLE__) || defined(GLEW_APPLE_GLX) +#elif !defined(GLEW_RAW_PTR) && !defined(GLEW_OSMESA) && !defined(GLEW_EGL) && !defined(__ANDROID__) && !defined(__native_client__) && !defined(__HAIKU__) && !defined(__APPLE__) || defined(GLEW_APPLE_GLX) GLboolean glxewIsSupported (const char* name) {