KiCad PCB EDA Suite
kicad.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2004-2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 2004-2021 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
31 #include <wx/filename.h>
32 #include <wx/log.h>
33 #include <wx/app.h>
34 #include <wx/stdpaths.h>
35 #include <wx/msgdlg.h>
36 
37 #include <filehistory.h>
38 #include <hotkeys_basic.h>
39 #include <kiway.h>
40 #include <paths.h>
42 #include <systemdirsappend.h>
44 
45 #include <stdexcept>
46 
47 #include "pgm_kicad.h"
48 #include "kicad_manager_frame.h"
49 #include "kicad_settings.h"
50 
51 #if defined( _WIN32 )
52 #include <config.h>
53 #include <VersionHelpers.h>
54 #endif
55 
56 // a dummy to quiet linking with EDA_BASE_FRAME::config();
57 #include <kiface_i.h>
59 {
60  // This function should never be called. It is only referenced from
61  // EDA_BASE_FRAME::config() and this is only provided to satisfy the linker,
62  // not to be actually called.
63  wxLogFatalError( wxT( "Unexpected call to Kiface() in kicad/kicad.cpp" ) );
64 
65  throw std::logic_error( "Unexpected call to Kiface() in kicad/kicad.cpp" );
66 }
67 
68 
70 
71 
73 {
74  return program;
75 }
76 
77 
78 // Similar to PGM_BASE& Pgm(), but return nullptr when a *.ki_face is run from a python script.
80 {
81  return &program;
82 }
83 
84 
86 {
87  return program;
88 }
89 
90 
92 {
93 #if defined(DEBUG)
94  wxString absoluteArgv0 = wxStandardPaths::Get().GetExecutablePath();
95 
96  if( !wxIsAbsolutePath( absoluteArgv0 ) )
97  {
98  wxLogError( wxT( "No meaningful argv[0]" ) );
99  return false;
100  }
101 #endif
102 
103  if( !InitPgm() )
104  return false;
105 
109  m_bm.Init();
110 
111  // Add search paths to feed the PGM_KICAD::SysSearch() function,
112  // currenly limited in support to only look for project templates
113  {
114  SEARCH_STACK bases;
115 
116  SystemDirsAppend( &bases );
117 
118  for( unsigned i = 0; i < bases.GetCount(); ++i )
119  {
120  wxFileName fn( bases[i], wxEmptyString );
121 
122  // Add KiCad template file path to search path list.
123  fn.AppendDir( wxT( "template" ) );
124 
125  // Only add path if exists and can be read by the user.
126  if( fn.DirExists() && fn.IsDirReadable() )
127  m_bm.m_search.AddPaths( fn.GetPath() );
128  }
129 
130  // The KICAD6_TEMPLATE_DIR takes precedence over the search stack template path.
131  ENV_VAR_MAP_CITER it = GetLocalEnvVariables().find( "KICAD6_TEMPLATE_DIR" );
132 
133  if( it != GetLocalEnvVariables().end() && it->second.GetValue() != wxEmptyString )
134  m_bm.m_search.Insert( it->second.GetValue(), 0 );
135 
136  // We've been adding system (installed default) search paths so far, now for user paths
137  // The default user search path is inside KIPLATFORM::ENV::GetDocumentsPath()
139 
140  // ...but the user can override that default with the KICAD_USER_TEMPLATE_DIR env var
141  it = GetLocalEnvVariables().find( "KICAD_USER_TEMPLATE_DIR" );
142 
143  if( it != GetLocalEnvVariables().end() && it->second.GetValue() != wxEmptyString )
144  m_bm.m_search.Insert( it->second.GetValue(), 0 );
145  }
146 
147  KICAD_MANAGER_FRAME* frame = new KICAD_MANAGER_FRAME( NULL, wxT( "KiCad" ),
148  wxDefaultPosition, wxSize( 775, -1 ) );
149  App().SetTopWindow( frame );
150 
151  Kiway.SetTop( frame );
152 
153  KICAD_SETTINGS* settings = static_cast<KICAD_SETTINGS*>( PgmSettings() );
154 
155  wxString projToLoad;
156 
157  if( App().argc > 1 )
158  {
159  wxFileName tmp = App().argv[1];
160 
161  if( tmp.GetExt() != ProjectFileExtension && tmp.GetExt() != LegacyProjectFileExtension )
162  {
163  wxString msg;
164 
165  msg.Printf( _( "File '%s'\ndoes not appear to be a valid KiCad project file." ),
166  tmp.GetFullPath() );
167  wxMessageDialog dlg( nullptr, msg, _( "Error" ), wxOK | wxICON_EXCLAMATION );
168  dlg.ShowModal();
169  }
170  else
171  {
172  projToLoad = tmp.GetFullPath();
173  }
174  }
175 
176  // If no file was given as an argument, check that there was a file open.
177  if( projToLoad.IsEmpty() && settings->m_OpenProjects.size() )
178  {
179  wxString last_pro = settings->m_OpenProjects.front();
180  settings->m_OpenProjects.erase( settings->m_OpenProjects.begin() );
181 
182  if( wxFileExists( last_pro ) )
183  {
184  // Try to open the last opened project,
185  // if a project name is not given when starting Kicad
186  projToLoad = last_pro;
187  }
188  }
189 
190  // Do not attempt to load a non-existent project file.
191  if( !projToLoad.empty() )
192  {
193  wxFileName fn( projToLoad );
194 
195  if( fn.Exists() )
196  {
197  fn.MakeAbsolute();
198  frame->LoadProject( fn );
199  }
200  }
201 
202  frame->Show( true );
203  frame->Raise();
204 
205  return true;
206 }
207 
208 
210 {
211  Kiway.OnKiwayEnd();
212 
213  if( m_settings_manager && m_settings_manager->IsOK() )
214  {
216  m_settings_manager->Save();
217  }
218 
219  // Destroy everything in PGM_KICAD,
220  // especially wxSingleInstanceCheckerImpl earlier than wxApp and earlier
221  // than static destruction would.
222  Destroy();
223 }
224 
225 
226 void PGM_KICAD::MacOpenFile( const wxString& aFileName )
227 {
228 #if defined(__WXMAC__)
229 
230  KICAD_MANAGER_FRAME* frame = (KICAD_MANAGER_FRAME*) App().GetTopWindow();
231 
232  if( !aFileName.empty() && wxFileExists( aFileName ) )
233  frame->LoadProject( wxFileName( aFileName ) );
234 
235 #endif
236 }
237 
238 
240 {
241  // unlike a normal destructor, this is designed to be called more
242  // than once safely:
243 
244  m_bm.End();
245 
247 }
248 
249 
251 
252 
256 struct APP_KICAD : public wxApp
257 {
258 #if defined (__LINUX__)
259  APP_KICAD(): wxApp()
260  {
261  // Disable proxy menu in Unity window manager. Only usual menubar works with
262  // wxWidgets (at least <= 3.1). When the proxy menu menubar is enable, some
263  // important things for us do not work: menuitems UI events and shortcuts.
264  wxString wm;
265 
266  if( wxGetEnv( wxT( "XDG_CURRENT_DESKTOP" ), &wm ) && wm.CmpNoCase( wxT( "Unity" ) ) == 0 )
267  {
268  wxSetEnv ( wxT("UBUNTU_MENUPROXY" ), wxT( "0" ) );
269  }
270 
271  // Force the use of X11 backend (or wayland-x11 compatibilty layer). This is
272  // required until wxWidgets supports the Wayland compositors
273  wxSetEnv( wxT( "GDK_BACKEND" ), wxT( "x11" ) );
274 
275  // Disable overlay scrollbars as they mess up wxWidgets window sizing and cause
276  // excessive redraw requests.
277  wxSetEnv( wxT( "GTK_OVERLAY_SCROLLING" ), wxT( "0" ) );
278 
279  // Set GTK2-style input instead of xinput2. This disables touchscreen and smooth
280  // scrolling. It's needed to ensure that we are not getting multiple mouse scroll
281  // events.
282  wxSetEnv( wxT( "GDK_CORE_DEVICE_EVENTS" ), wxT( "1" ) );
283  }
284 #endif
285 
286  bool OnInit() override
287  {
288 #if defined( _MSC_VER ) && defined( DEBUG )
289  // wxWidgets turns on leak dumping in debug but its "flawed" and will falsely dump
290  // for half a hour _CRTDBG_ALLOC_MEM_DF is the usual default for MSVC.
291  _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF );
292 #endif
293 
294 #if defined( _WIN32 ) && defined( PYTHON_VERSION_MAJOR ) \
295  && ( ( PYTHON_VERSION_MAJOR == 3 && PYTHON_VERSION_MINOR >= 8 ) \
296  || PYTHON_VERSION_MAJOR > 3 )
297 
298  // Python 3.8 switched to Windows 8+ API, we do not support Windows 7 and will not
299  // attempt to hack around it. Gracefully inform the user and refuse to start (because
300  // python will crash us if we continue).
301  if( !IsWindows8OrGreater() )
302  {
303  wxMessageBox( _( "Windows 7 and older is no longer supported by KiCad and its "
304  "dependencies." ), _( "Unsupported Operating System" ),
305  wxOK | wxICON_ERROR );
306  return false;
307  }
308 #endif
309 
310  if( !program.OnPgmInit() )
311  {
312  program.OnPgmExit();
313  return false;
314  }
315 
316  return true;
317  }
318 
319  int OnExit() override
320  {
321  program.OnPgmExit();
322 
323 #if defined(__FreeBSD__)
324  // Avoid wxLog crashing when used in destructors.
325  wxLog::EnableLogging( false );
326 #endif
327 
328  return wxApp::OnExit();
329  }
330 
331  int OnRun() override
332  {
333  try
334  {
335  return wxApp::OnRun();
336  }
337  catch( const std::exception& e )
338  {
339  wxLogError( wxT( "Unhandled exception class: %s what: %s" ),
340  FROM_UTF8( typeid( e ).name() ), FROM_UTF8( e.what() ) );
341  }
342  catch( const IO_ERROR& ioe )
343  {
344  wxLogError( ioe.What() );
345  }
346  catch(...)
347  {
348  wxLogError( wxT( "Unhandled exception of unknown type" ) );
349  }
350 
351  return -1;
352  }
353 
354  int FilterEvent( wxEvent& aEvent ) override
355  {
356  if( aEvent.GetEventType() == wxEVT_SHOW )
357  {
358  wxShowEvent& event = static_cast<wxShowEvent&>( aEvent );
359  wxDialog* dialog = dynamic_cast<wxDialog*>( event.GetEventObject() );
360 
361  if( dialog && dialog->IsModal() )
362  Pgm().m_ModalDialogCount += event.IsShown() ? 1 : -1;
363  }
364 
365  return Event_Skip;
366  }
367 
373 #if defined( __WXMAC__ )
374  void MacOpenFile( const wxString& aFileName ) override
375  {
376  Pgm().MacOpenFile( aFileName );
377  }
378 #endif
379 };
380 
381 IMPLEMENT_APP( APP_KICAD )
382 
383 
384 // The C++ project manager supports one open PROJECT, so Prj() calls within
385 // this link image need this function.
387 {
388  return Kiway.Prj();
389 }
390 
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition: pgm_base.h:167
#define KFCTL_CPP_PROJECT_SUITE
Running under C++ project mgr, possibly with others.
Definition: kiway.h:156
A KIFACE (I)mplementation.
Definition: kiface_i.h:37
Container for project specific data.
Definition: project.h:62
static wxString FROM_UTF8(const char *cstring)
Convert a UTF8 encoded C string to a wxString for all wxWidgets build modes.
Definition: macros.h:110
int OnExit() override
Definition: kicad.cpp:319
void Init()
Definition: bin_mod.cpp:41
void SaveCommonSettings()
Save the program (process) settings subset which are stored .kicad_common.
Definition: pgm_base.cpp:541
const std::string ProjectFileExtension
Container for data for KiCad programs.
Definition: pgm_base.h:131
PGM_KICAD extends PGM_BASE to bring in FileHistory() and PdfBrowser() which were moved from EDA_APP i...
Definition: pgm_kicad.h:38
int m_ModalDialogCount
Definition: pgm_base.h:333
PROJECT & Prj()
Definition: kicad.cpp:386
virtual PROJECT & Prj() const
Return the PROJECT associated with this KIWAY.
Definition: kiway.cpp:174
virtual void MacOpenFile(const wxString &aFileName)=0
Specific to MacOSX (not used under Linux or Windows).
void MacOpenFile(const wxString &aFileName) override
Specific to MacOSX (not used under Linux or Windows).
Definition: kicad.cpp:226
virtual wxApp & App()
Returns a bare naked wxApp which may come from wxPython, SINGLE_TOP, or kicad.exe.
Definition: pgm_base.cpp:140
void Destroy()
Definition: pgm_base.cpp:129
System directories search utilities.
virtual const ENV_VAR_MAP & GetLocalEnvVariables() const
Definition: pgm_base.h:290
Look for files in a number of paths.
Definition: search_stack.h:41
bool OnPgmInit()
Definition: kicad.cpp:91
std::vector< wxString > m_OpenProjects
void OnKiwayEnd()
Definition: kiway.cpp:602
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
Definition: kicad.cpp:58
int FilterEvent(wxEvent &aEvent) override
Definition: kicad.cpp:354
std::unique_ptr< SETTINGS_MANAGER > m_settings_manager
Definition: pgm_base.h:349
bool OnInit() override
Definition: kicad.cpp:286
static PGM_KICAD program
Definition: kicad.cpp:69
void Destroy()
Definition: kicad.cpp:239
void SetKiway(KIWAY *aKiway)
Associate this setting manager with the given Kiway.
#define NULL
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:29
std::map< wxString, ENV_VAR_ITEM >::const_iterator ENV_VAR_MAP_CITER
Definition: pgm_base.h:115
Definition of file extensions used in Kicad.
static wxString GetUserTemplatesPath()
Gets the user path for custom templates.
Definition: paths.cpp:85
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
Definition: kiway.h:260
void SystemDirsAppend(SEARCH_STACK *aSearchStack)
Append system places to aSearchStack in a platform specific way and pertinent to KiCad programs.
PGM_BASE & Pgm()
The global Program "get" accessor.
Definition: kicad.cpp:72
void InitSettings(APP_SETTINGS_BASE *aPtr)
Takes ownership of a new application settings object.
Definition: bin_mod.h:61
const std::string LegacyProjectFileExtension
void SetTop(wxFrame *aTop)
Tell this KIWAY about the top most frame in the program and optionally allows it to play the role of ...
Definition: kiway.cpp:80
PGM_KICAD & PgmTop()
Definition: kicad.cpp:85
SEARCH_STACK m_search
Definition: bin_mod.h:68
int OnRun() override
Definition: kicad.cpp:331
JSON_SETTINGS * RegisterSettings(JSON_SETTINGS *aSettings, bool aLoadNow=true)
Takes ownership of the pointer passed in.
BIN_MOD m_bm
Definition: pgm_kicad.h:68
const char * name
Definition: DXF_plotter.cpp:59
#define _(s)
Definition: 3d_actions.cpp:33
PGM_BASE * PgmOrNull()
similar to PGM_BASE& Pgm(), but return a reference that can be nullptr when running a shared lib from...
Definition: kicad.cpp:79
APP_SETTINGS_BASE * PgmSettings()
Definition: pgm_kicad.h:55
bool InitPgm()
Initialize this program.
Definition: pgm_base.cpp:215
void LoadProject(const wxFileName &aProjectFileName)
void OnPgmExit()
Definition: kicad.cpp:209
Not publicly visible because most of the action is in PGM_KICAD these days.
Definition: kicad.cpp:256
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Definition: ki_exception.h:75
The main KiCad project manager frame.
void AddPaths(const wxString &aPaths, int aIndex=-1)
Insert or append path(s).
KIWAY Kiway
void End()
Definition: bin_mod.cpp:53