Skip to content

Commit

Permalink
Add initial support for Phoenix (new wxPython binding)
Browse files Browse the repository at this point in the history
Based on the work of @mmccoo:
https://kicad.mmccoo.com/2017/11/23/learnings-from-moving-kicad-to-wxpython-4-0/

Please note that wxpy_api.h is currently not distributed in Phoenix.
As workaround it is required to manually copy the file from the repo
onto your system where cmake can find it.

file: https://github.com/wxWidgets/Phoenix/blob/master/src/wxpy_api.h
  • Loading branch information
pointhi committed Aug 15, 2018
1 parent 036263c commit b70b779
Show file tree
Hide file tree
Showing 8 changed files with 171 additions and 3 deletions.
33 changes: 31 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ option( KICAD_SCRIPTING_WXPYTHON
"Build wxPython implementation for wx interface building in Python and py.shell (default ON)."
ON )

option( KICAD_SCRIPTING_WXPYTHON_PHOENIX
"Use new wxPython binding (default OFF)."
OFF )

option( KICAD_SCRIPTING_ACTION_MENU
"Build a tools menu with registered python plugins: actions plugins (default OFF)."
)
Expand Down Expand Up @@ -382,6 +386,10 @@ if( KICAD_SCRIPTING_WXPYTHON )
add_definitions( -DKICAD_SCRIPTING_WXPYTHON )
endif()

if( KICAD_SCRIPTING_WXPYTHON_PHOENIX )
add_definitions( -DKICAD_SCRIPTING_WXPYTHON_PHOENIX )
endif()

if( KICAD_SCRIPTING_ACTION_MENU )
add_definitions( -DKICAD_SCRIPTING_ACTION_MENU )
endif()
Expand Down Expand Up @@ -704,6 +712,11 @@ if( KICAD_SCRIPTING OR KICAD_SCRIPTING_MODULES )
find_package( SWIG 3.0 REQUIRED )
include( ${SWIG_USE_FILE} )

if( KICAD_SCRIPTING_WXPYTHON_PHOENIX )
# In case of Phoenix we also require SIP
find_package( SIP REQUIRED )
endif()

if( KICAD_SCRIPTING_PYTHON3 )
set( PythonInterp_FIND_VERSION 3.3 )
set( PythonLibs_FIND_VERSION 3.3 )
Expand Down Expand Up @@ -758,8 +771,24 @@ if( KICAD_SCRIPTING OR KICAD_SCRIPTING_MODULES )
if( KICAD_SCRIPTING_WXPYTHON )
# Check to see if the correct version of wxPython is installed based on the version of
# wxWidgets found. At least the major an minor version should match.
set( _wxpy_version "${wxWidgets_VERSION_MAJOR}.${wxWidgets_VERSION_MINOR}" )
set( _py_cmd "import wxversion;print(wxversion.checkInstalled('${_wxpy_version}'))" )
if( KICAD_SCRIPTING_WXPYTHON_PHOENIX )
set( _py_cmd "import wx;print(wx.version())" )
execute_process( COMMAND ${PYTHON_EXECUTABLE} -c "${_py_cmd}"
RESULT_VARIABLE WXPYTHON_VERSION_RESULT
OUTPUT_VARIABLE WXPYTHON_VERSION_FOUND
OUTPUT_STRIP_TRAILING_WHITESPACE
)
# Check to see if any version of wxPython is installed on the system.
if( WXPYTHON_VERSION_RESULT GREATER 0 )
message( FATAL_ERROR "wxPython does not appear to be installed on the system." )
endif()
set( _wxpy_version ${WXPYTHON_VERSION_FOUND} )
set( _py_cmd "import wx;import re;print(re.search('wxWidgets ${wxWidgets_VERSION_MAJOR}.${wxWidgets_VERSION_MINOR}', wx.wxWidgets_version) != None)" )
else()
set( _wxpy_version "${wxWidgets_VERSION_MAJOR}.${wxWidgets_VERSION_MINOR}" )
set( _py_cmd "import wxversion;print(wxversion.checkInstalled('${_wxpy_version}'))" )
endif()


# Add user specified Python site package path.
if( PYTHON_SITE_PACKAGE_PATH )
Expand Down
58 changes: 58 additions & 0 deletions CMakeModules/FindSIP.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Find SIP
# ~~~~~~~~
#
# SIP website: http://www.riverbankcomputing.co.uk/sip/index.php
#
# Find the installed version of SIP. FindSIP should be called after Python
# has been found.
#
# This file defines the following variables:
#
# SIP_VERSION - The version of SIP found expressed as a 6 digit hex number
# suitable for comparison as a string.
#
# SIP_VERSION_STR - The version of SIP found as a human readable string.
#
# SIP_BINARY_PATH - Path and filename of the SIP command line executable.
#
# SIP_INCLUDE_DIR - Directory holding the SIP C++ header file.
#
# SIP_DEFAULT_SIP_DIR - Default directory where .sip files should be installed
# into.

# Copyright (c) 2007, Simon Edwards <[email protected]>
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.



IF(SIP_VERSION)
# Already in cache, be silent
SET(SIP_FOUND TRUE)
ELSE(SIP_VERSION)

FIND_FILE(_find_sip_py FindSIP.py PATHS ${CMAKE_MODULE_PATH})

EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} ${_find_sip_py} OUTPUT_VARIABLE sip_config)
IF(sip_config)
STRING(REGEX REPLACE "^sip_version:([^\n]+).*$" "\\1" SIP_VERSION ${sip_config})
STRING(REGEX REPLACE ".*\nsip_version_num:([^\n]+).*$" "\\1" SIP_VERSION_NUM ${sip_config})
STRING(REGEX REPLACE ".*\nsip_version_str:([^\n]+).*$" "\\1" SIP_VERSION_STR ${sip_config})
STRING(REGEX REPLACE ".*\nsip_bin:([^\n]+).*$" "\\1" SIP_BINARY_PATH ${sip_config})
STRING(REGEX REPLACE ".*\ndefault_sip_dir:([^\n]+).*$" "\\1" SIP_DEFAULT_SIP_DIR ${sip_config})
STRING(REGEX REPLACE ".*\nsip_inc_dir:([^\n]+).*$" "\\1" SIP_INCLUDE_DIR ${sip_config})
STRING(REGEX REPLACE ".*\nsip_module_dir:([^\n]+).*$" "\\1" SIP_MODULE_DIR ${sip_config})
SET(SIP_FOUND TRUE)
ENDIF(sip_config)

IF(SIP_FOUND)
IF(NOT SIP_FIND_QUIETLY)
MESSAGE(STATUS "Found SIP version: ${SIP_VERSION_STR}")
ENDIF(NOT SIP_FIND_QUIETLY)
ELSE(SIP_FOUND)
IF(SIP_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "Could not find SIP")
ENDIF(SIP_FIND_REQUIRED)
ENDIF(SIP_FOUND)

ENDIF(SIP_VERSION)
46 changes: 46 additions & 0 deletions CMakeModules/FindSIP.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) 2007, Simon Edwards <[email protected]>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the Simon Edwards <[email protected]> nor the
# names of its contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY Simon Edwards <[email protected]> ''AS IS'' AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL Simon Edwards <[email protected]> BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# FindSIP.py
# Copyright (c) 2007, Simon Edwards <[email protected]>
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.

import sipconfig

sipcfg = sipconfig.Configuration()
print("sip_version:%06.0x" % sipcfg.sip_version)
print("sip_version_num:%d" % sipcfg.sip_version)
print("sip_version_str:%s" % sipcfg.sip_version_str)
print("sip_bin:%s" % sipcfg.sip_bin)
print("default_sip_dir:%s" % sipcfg.default_sip_dir)
print("sip_inc_dir:%s" % sipcfg.sip_inc_dir)
# SIP 4.19.10+ has new sipcfg.sip_module_dir
if hasattr(sipcfg, "sip_module_dir"):
print("sip_module_dir:%s" % sipcfg.sip_module_dir)
else:
print("sip_module_dir:%s" % sipcfg.sip_mod_dir)
5 changes: 5 additions & 0 deletions Documentation/development/compiling.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@ of Python 2. This option is disabled by default.
The KICAD_SCRIPTING_WXPYTHON option is used to enable building the wxPython interface into
Pcbnew including the wxPython console. This option is enabled by default.

## wxPython Phoenix Scripting Support ## {#wxpython_phoenix}

The KICAD_SCRIPTING_WXPYTHON_PHOENIX option is used to enable building the wxPython interface with
the new Phoenix binding instead of the legacy one. This option is disabled by default.

## GitHub Plugin ## {#github_opt}

The BUILD_GITHUB_PLUGIN option is used to control if the GitHub plug in is built. This option is
Expand Down
7 changes: 7 additions & 0 deletions common/dialog_about/dialog_about.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,13 @@ void DIALOG_ABOUT::buildVersionInfoData( wxString& aMsg, bool aFormatHtml )
aMsg << OFF;
#endif

aMsg << indent4 << "KICAD_SCRIPTING_WXPYTHON_PHOENIX=";
#ifdef KICAD_SCRIPTING_WXPYTHON_PHOENIX
aMsg << ON;
#else
aMsg << OFF;
#endif

aMsg << indent4 << "KICAD_SCRIPTING_ACTION_MENU=";
#ifdef KICAD_SCRIPTING_ACTION_MENU
aMsg << ON;
Expand Down
3 changes: 3 additions & 0 deletions pcbnew/python/kicad_pyshell/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ def _setup(self):
self.autoSaveHistory = False
self.LoadSettings()

# keep pointer to app object so garbage collector does not remove it.
self.theApp = wx.App()

self.crust = crust.Crust(parent=self.notebook,
intro=intro, locals=namespace,
rootLabel="locals()",
Expand Down
14 changes: 14 additions & 0 deletions pcbnew/swig/python_scripting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,11 @@ bool pcbnewInitPythonScripting( const char * aUserScriptingPath )
// Make sure that that the correct version of wxPython is loaded. In systems where there
// are different versions of wxPython installed this can lead to select wrong wxPython
// version being selected.
#ifdef KICAD_SCRIPTING_WXPYTHON_PHOENIX
snprintf( cmd, sizeof(cmd), "import wx" );
#else
snprintf( cmd, sizeof( cmd ), "import wxversion; wxversion.select( '%s' )", WXPYTHON_VERSION );
#endif

int retv = PyRun_SimpleString( cmd );

Expand All @@ -180,6 +184,7 @@ bool pcbnewInitPythonScripting( const char * aUserScriptingPath )
}
#endif // ifndef __WINDOWS__

#ifndef KICAD_SCRIPTING_WXPYTHON_PHOENIX
// Load the wxPython core API. Imports the wx._core_ module and sets a
// local pointer to a function table located there. The pointer is used
// internally by the rest of the API functions.
Expand All @@ -190,6 +195,7 @@ bool pcbnewInitPythonScripting( const char * aUserScriptingPath )
Py_Finalize();
return false;
}
#endif

wxPythonLoaded = true;

Expand Down Expand Up @@ -370,7 +376,11 @@ wxWindow* CreatePythonShellWindow( wxWindow* parent, const wxString& aFramenameI
// use of another wxPython API to take a wxWindows object and build a
// wxPython object that wraps it.

#ifdef KICAD_SCRIPTING_WXPYTHON_PHOENIX
PyObject* arg = wxPyConstructObject( parent, "wxWindow", false );
#else
PyObject* arg = wxPyMake_wxObject( parent, false );
#endif
wxASSERT( arg != NULL );

PyObject* tuple = PyTuple_New( 1 );
Expand All @@ -385,7 +395,11 @@ wxWindow* CreatePythonShellWindow( wxWindow* parent, const wxString& aFramenameI
{
// Otherwise, get the returned window out of Python-land and
// into C++-ville...
#ifdef KICAD_SCRIPTING_WXPYTHON_PHOENIX
bool success = wxPyConvertWrappedPtr( result, (void**) &window, "wxWindow" );
#else
bool success = wxPyConvertSwigPtr( result, (void**) &window, "wxWindow" );
#endif
(void) success;

wxASSERT_MSG( success, "Returned object was not a wxWindow!" );
Expand Down
8 changes: 7 additions & 1 deletion pcbnew/swig/python_scripting.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,13 @@

#ifndef NO_WXPYTHON_EXTENSION_HEADERS
#ifdef KICAD_SCRIPTING_WXPYTHON
#include <wx/wxPython/wxPython.h>
#ifdef KICAD_SCRIPTING_WXPYTHON_PHOENIX
#include <sip.h> // required by wxpy_api.h
#include <wxpy_api.h>
#include <wx/window.h>
#else
#include <wx/wxPython/wxPython.h>
#endif
#endif
#endif

Expand Down

7 comments on commit b70b779

@mmccoo
Copy link

@mmccoo mmccoo commented on b70b779 Aug 27, 2018 via email

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pointhi
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, the python3 branch misses some testing on mac (KiCad/kicad-mac-builder#205). When this is finished it seems we can merge Python3 support and focus on wxPython.

For wxPython it is the same process. Getting it verified on windows and mac and then merge into upstream (https://bugs.launchpad.net/kicad/+bug/1785119).

For wxpy_api.h, I will look to port the required code into kicad if possible. If that is not possible, we can copy the file into the KiCad sources (If license permits).

@mmccoo
Copy link

@mmccoo mmccoo commented on b70b779 Aug 29, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello Thomas,
Are you on the kicad team, one of the CERN folks? I don't know that I'd seen your name before.
If so, perhaps you can help get a patch of mine approved/merged. It's sort of been in purgatory. I submitted it twice with no rejection or merge.

I have a proposed patch to remove the dependence on pywx_api.h
I put a copy here

I don't see a way to attach files to comments.

Before I describe the change, a comment about wxpython and wxwidgets. I found that in order to compile kicad, I needed wxwidgets installed. (not entirely trivial due to kicad sitting in gtk2). I also need wxpython phoenix installed. of course. The thing is that wxpython has its own copy of wxwidgets. If you let pcbnew just use the installed wxWidgets, you could get an error like this:
ImportError: /usr/local/lib/python2.7/dist-packages/wx/_core.so: symbol _ZN13wxWindowIDRef6AssignEi, version WXU_3.0 not defined in file libwx_gtk2u_core-3.0.so.0 with link time reference

In any case, to talk about the proposed patch.

The dependence on pywx_api is pretty small.

  • starting and stopping threads (which I inlined; just single calls to Py)
  • passing pcb_edit_frame into creation of the scripting window and then passing the result back. Instead of pointers (whose conversion would need pywx), I just pass window ids.

Another difference is that I changed the way the window creation stuff is invoked. Before, it would create a python function and then call it. Instead, I'm just calling some python code. Perhaps, the other/old way is more "pythonic", but I think it's just roundabout.

@pointhi
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @mmccoo,

I'm in the kicad team as library maintainer, so no write access for the code :). You could post the patch on launchpad, and poke @nickoe or @c4757p on IRC about it.

Thanks for the clarification of the pywx_api stuff. I will try to implement it soon. For wxpython, I only tested it with Python3 so there was no wxpython conflict.

@pointhi
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mmccoo,

It seems you did some additional patching which is not visible in https://mmccoo.com/random/diffs_for_phoenix. Could you please give me a link to the extended patch? This would simplify things for me quite a bit to get the stuff finished.

@mmccoo
Copy link

@mmccoo mmccoo commented on b70b779 Aug 30, 2018 via email

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pointhi
Copy link
Owner Author

@pointhi pointhi commented on b70b779 Aug 30, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thx, I incoperated your changes and it seems to work fine.

The lib stuff is annoying. Wonder why it didn't happen in the past.

LD_PRELOAD=/usr/lib/python3.7/site-packages/wx/libwx_gtk3u_core-3.0.so pcbnew

I reported it: wxWidgets/Phoenix#982

Please sign in to comment.