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 <macros.h>
41 #include <paths.h>
42 #include <richio.h>
44 #include <systemdirsappend.h>
45 #include <trace_helpers.h>
47 
48 #include <stdexcept>
49 
50 #include "pgm_kicad.h"
51 #include "kicad_manager_frame.h"
52 #include "kicad_settings.h"
53 
54 #include <kiplatform/app.h>
55 #include <kiplatform/environment.h>
56 
57 
58 // a dummy to quiet linking with EDA_BASE_FRAME::config();
59 #include <kiface_i.h>
61 {
62  // This function should never be called. It is only referenced from
63  // EDA_BASE_FRAME::config() and this is only provided to satisfy the linker,
64  // not to be actually called.
65  wxLogFatalError( wxT( "Unexpected call to Kiface() in kicad/kicad.cpp" ) );
66 
67  throw std::logic_error( "Unexpected call to Kiface() in kicad/kicad.cpp" );
68 }
69 
70 
72 
73 
75 {
76  return program;
77 }
78 
79 
80 // Similar to PGM_BASE& Pgm(), but return nullptr when a *.ki_face is run from a python script.
82 {
83  return &program;
84 }
85 
86 
88 {
89  return program;
90 }
91 
92 
94 {
95  App().SetAppDisplayName( wxT( "KiCad" ) );
96 
97 #if defined(DEBUG)
98  wxString absoluteArgv0 = wxStandardPaths::Get().GetExecutablePath();
99 
100  if( !wxIsAbsolutePath( absoluteArgv0 ) )
101  {
102  wxLogError( wxT( "No meaningful argv[0]" ) );
103  return false;
104  }
105 #endif
106 
107  if( !InitPgm() )
108  return false;
109 
113  m_bm.Init();
114 
115  // Add search paths to feed the PGM_KICAD::SysSearch() function,
116  // currently limited in support to only look for project templates
117  {
118  SEARCH_STACK bases;
119 
120  SystemDirsAppend( &bases );
121 
122  for( unsigned i = 0; i < bases.GetCount(); ++i )
123  {
124  wxFileName fn( bases[i], wxEmptyString );
125 
126  // Add KiCad template file path to search path list.
127  fn.AppendDir( wxT( "template" ) );
128 
129  // Only add path if exists and can be read by the user.
130  if( fn.DirExists() && fn.IsDirReadable() )
131  m_bm.m_search.AddPaths( fn.GetPath() );
132  }
133 
134  // The KICAD6_TEMPLATE_DIR takes precedence over the search stack template path.
135  ENV_VAR_MAP_CITER it = GetLocalEnvVariables().find( "KICAD6_TEMPLATE_DIR" );
136 
137  if( it != GetLocalEnvVariables().end() && it->second.GetValue() != wxEmptyString )
138  m_bm.m_search.Insert( it->second.GetValue(), 0 );
139 
140  // We've been adding system (installed default) search paths so far, now for user paths
141  // The default user search path is inside KIPLATFORM::ENV::GetDocumentsPath()
143 
144  // ...but the user can override that default with the KICAD_USER_TEMPLATE_DIR env var
145  it = GetLocalEnvVariables().find( "KICAD_USER_TEMPLATE_DIR" );
146 
147  if( it != GetLocalEnvVariables().end() && it->second.GetValue() != wxEmptyString )
148  m_bm.m_search.Insert( it->second.GetValue(), 0 );
149  }
150 
151  KICAD_MANAGER_FRAME* frame = new KICAD_MANAGER_FRAME( NULL, wxT( "KiCad" ),
152  wxDefaultPosition, wxSize( 775, -1 ) );
153  App().SetTopWindow( frame );
154 
155  Kiway.SetTop( frame );
156 
157  KICAD_SETTINGS* settings = static_cast<KICAD_SETTINGS*>( PgmSettings() );
158 
159  wxString projToLoad;
160 
161  if( App().argc > 1 )
162  {
163  wxFileName tmp = App().argv[1];
164 
165  if( tmp.GetExt() != ProjectFileExtension && tmp.GetExt() != LegacyProjectFileExtension )
166  {
167  wxString msg;
168 
169  msg.Printf( _( "File '%s'\ndoes not appear to be a valid KiCad project file." ),
170  tmp.GetFullPath() );
171  wxMessageDialog dlg( nullptr, msg, _( "Error" ), wxOK | wxICON_EXCLAMATION );
172  dlg.ShowModal();
173  }
174  else
175  {
176  projToLoad = tmp.GetFullPath();
177  }
178  }
179 
180  // If no file was given as an argument, check that there was a file open.
181  if( projToLoad.IsEmpty() && settings->m_OpenProjects.size() )
182  {
183  wxString last_pro = settings->m_OpenProjects.front();
184  settings->m_OpenProjects.erase( settings->m_OpenProjects.begin() );
185 
186  if( wxFileExists( last_pro ) )
187  {
188  // Try to open the last opened project,
189  // if a project name is not given when starting Kicad
190  projToLoad = last_pro;
191  }
192  }
193 
194  // Do not attempt to load a non-existent project file.
195  if( !projToLoad.empty() )
196  {
197  wxFileName fn( projToLoad );
198 
199  if( fn.Exists() )
200  {
201  fn.MakeAbsolute();
202  frame->LoadProject( fn );
203  }
204  }
205 
206  frame->Show( true );
207  frame->Raise();
208 
209  return true;
210 }
211 
212 
214 {
215  Kiway.OnKiwayEnd();
216 
217  if( m_settings_manager && m_settings_manager->IsOK() )
218  {
220  m_settings_manager->Save();
221  }
222 
223  // Destroy everything in PGM_KICAD,
224  // especially wxSingleInstanceCheckerImpl earlier than wxApp and earlier
225  // than static destruction would.
226  Destroy();
227 }
228 
229 
230 void PGM_KICAD::MacOpenFile( const wxString& aFileName )
231 {
232 #if defined(__WXMAC__)
233 
234  KICAD_MANAGER_FRAME* frame = (KICAD_MANAGER_FRAME*) App().GetTopWindow();
235 
236  if( !aFileName.empty() && wxFileExists( aFileName ) )
237  frame->LoadProject( wxFileName( aFileName ) );
238 
239 #endif
240 }
241 
242 
244 {
245  // unlike a normal destructor, this is designed to be called more
246  // than once safely:
247 
248  m_bm.End();
249 
251 }
252 
253 
255 
256 
260 struct APP_KICAD : public wxApp
261 {
262  APP_KICAD() : wxApp()
263  {
264  // Init the environment each platform wants
266  }
267 
268 
269  bool OnInit() override
270  {
271  // Perform platform-specific init tasks
272  if( !KIPLATFORM::APP::Init() )
273  return false;
274 
275  if( !program.OnPgmInit() )
276  {
277  program.OnPgmExit();
278  return false;
279  }
280 
281  return true;
282  }
283 
284  int OnExit() override
285  {
286  program.OnPgmExit();
287 
288 #if defined(__FreeBSD__)
289  // Avoid wxLog crashing when used in destructors.
290  wxLog::EnableLogging( false );
291 #endif
292 
293  return wxApp::OnExit();
294  }
295 
296  int OnRun() override
297  {
298  try
299  {
300  return wxApp::OnRun();
301  }
302  catch( const std::exception& e )
303  {
304  wxLogError( wxT( "Unhandled exception class: %s what: %s" ),
305  FROM_UTF8( typeid( e ).name() ), FROM_UTF8( e.what() ) );
306  }
307  catch( const IO_ERROR& ioe )
308  {
309  wxLogError( ioe.What() );
310  }
311  catch(...)
312  {
313  wxLogError( wxT( "Unhandled exception of unknown type" ) );
314  }
315 
316  return -1;
317  }
318 
319  int FilterEvent( wxEvent& aEvent ) override
320  {
321  if( aEvent.GetEventType() == wxEVT_SHOW )
322  {
323  wxShowEvent& event = static_cast<wxShowEvent&>( aEvent );
324  wxDialog* dialog = dynamic_cast<wxDialog*>( event.GetEventObject() );
325 
326  if( dialog && dialog->IsModal() )
327  Pgm().m_ModalDialogCount += event.IsShown() ? 1 : -1;
328  }
329 
330  return Event_Skip;
331  }
332 
333 #if defined( DEBUG )
334 
337  bool ProcessEvent( wxEvent& aEvent ) override
338  {
339  if( aEvent.GetEventType() == wxEVT_CHAR || aEvent.GetEventType() == wxEVT_CHAR_HOOK )
340  {
341  wxKeyEvent* keyEvent = static_cast<wxKeyEvent*>( &aEvent );
342 
343  if( keyEvent )
344  {
345  wxLogTrace( kicadTraceKeyEvent, "APP_KICAD::ProcessEvent %s", dump( *keyEvent ) );
346  }
347  }
348 
349  aEvent.Skip();
350  return false;
351  }
352 
360  bool OnExceptionInMainLoop() override
361  {
362  try
363  {
364  throw;
365  }
366  catch( const std::exception& e )
367  {
368  wxLogError( "Unhandled exception class: %s what: %s",
369  FROM_UTF8( typeid(e).name() ),
370  FROM_UTF8( e.what() ) );
371  }
372  catch( const IO_ERROR& ioe )
373  {
374  wxLogError( ioe.What() );
375  }
376  catch(...)
377  {
378  wxLogError( "Unhandled exception of unknown type" );
379  }
380 
381  return false; // continue on. Return false to abort program
382  }
383 #endif
384 
390 #if defined( __WXMAC__ )
391  void MacOpenFile( const wxString& aFileName ) override
392  {
393  Pgm().MacOpenFile( aFileName );
394  }
395 #endif
396 };
397 
398 IMPLEMENT_APP( APP_KICAD )
399 
400 
401 // The C++ project manager supports one open PROJECT, so Prj() calls within
402 // this link image need this function.
404 {
405  return Kiway.Prj();
406 }
407 
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition: pgm_base.h:129
#define KFCTL_CPP_PROJECT_SUITE
Running under C++ project mgr, possibly with others.
Definition: kiway.h:155
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:284
void Init()
Definition: bin_mod.cpp:38
void SaveCommonSettings()
Save the program (process) settings subset which are stored .kicad_common.
Definition: pgm_base.cpp:367
const std::string ProjectFileExtension
Container for data for KiCad programs.
Definition: pgm_base.h:93
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:291
PROJECT & Prj()
Definition: kicad.cpp:403
virtual PROJECT & Prj() const
Return the PROJECT associated with this KIWAY.
Definition: kiway.cpp:186
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:230
virtual wxApp & App()
Returns a bare naked wxApp which may come from wxPython, SINGLE_TOP, or kicad.exe.
Definition: pgm_base.cpp:131
void Destroy()
Definition: pgm_base.cpp:123
System directories search utilities.
Look for files in a number of paths.
Definition: search_stack.h:41
bool OnPgmInit()
Definition: kicad.cpp:93
std::vector< wxString > m_OpenProjects
void OnKiwayEnd()
Definition: kiway.cpp:630
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
Definition: kicad.cpp:60
This file contains miscellaneous commonly used macros and functions.
int FilterEvent(wxEvent &aEvent) override
Definition: kicad.cpp:319
std::unique_ptr< SETTINGS_MANAGER > m_settings_manager
Definition: pgm_base.h:307
bool OnInit() override
Definition: kicad.cpp:269
static PGM_KICAD program
Definition: kicad.cpp:71
void Destroy()
Definition: kicad.cpp:243
void SetKiway(KIWAY *aKiway)
Associate this setting manager with the given Kiway.
#define NULL
wxString dump(const wxArrayString &aArray)
Debug helper for printing wxArrayString contents.
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:30
Definition of file extensions used in Kicad.
static wxString GetUserTemplatesPath()
Gets the user path for custom templates.
Definition: paths.cpp:86
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
Definition: kiway.h:258
#define _(s)
void SystemDirsAppend(SEARCH_STACK *aSearchStack)
Append system places to aSearchStack in a platform specific way and pertinent to KiCad programs.
wxLogTrace helper definitions.
PGM_BASE & Pgm()
The global Program "get" accessor.
Definition: kicad.cpp:74
void InitSettings(APP_SETTINGS_BASE *aPtr)
Takes ownership of a new application settings object.
Definition: bin_mod.h:53
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:82
PGM_KICAD & PgmTop()
Definition: kicad.cpp:87
bool Init()
Perform application-specific initialization tasks.
Definition: gtk/app.cpp:40
SEARCH_STACK m_search
Definition: bin_mod.h:60
int OnRun() override
Definition: kicad.cpp:296
JSON_SETTINGS * RegisterSettings(JSON_SETTINGS *aSettings, bool aLoadNow=true)
Takes ownership of the pointer passed in.
bool InitPgm(bool aHeadless=false)
Initialize this program.
Definition: pgm_base.cpp:203
BIN_MOD m_bm
Definition: pgm_kicad.h:68
const char * name
Definition: DXF_plotter.cpp:59
void Init()
Perform environment initialization tasks.
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:81
APP_SETTINGS_BASE * PgmSettings()
Definition: pgm_kicad.h:55
const wxChar *const kicadTraceKeyEvent
Flag to enable wxKeyEvent debug tracing.
void LoadProject(const wxFileName &aProjectFileName)
APP_KICAD()
Definition: kicad.cpp:262
std::map< wxString, ENV_VAR_ITEM >::const_iterator ENV_VAR_MAP_CITER
void OnPgmExit()
Definition: kicad.cpp:213
Not publicly visible because most of the action is in PGM_KICAD these days.
Definition: kicad.cpp:260
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Definition: ki_exception.h:75
virtual ENV_VAR_MAP & GetLocalEnvVariables() const
Definition: pgm_base.cpp:633
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:50