KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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#include <wx/cmdline.h>
37
38#include <file_history.h>
39#include <hotkeys_basic.h>
40#include <kiway.h>
41#include <macros.h>
42#include <paths.h>
43#include <richio.h>
46#include <systemdirsappend.h>
47#include <trace_helpers.h>
49
50#include <stdexcept>
51
52#include "pgm_kicad.h"
53#include "kicad_manager_frame.h"
54
55#include <kiplatform/app.h>
57
58
59// a dummy to quiet linking with EDA_BASE_FRAME::config();
60#include <kiface_base.h>
62{
63 // This function should never be called. It is only referenced from
64 // EDA_BASE_FRAME::config() and this is only provided to satisfy the linker,
65 // not to be actually called.
66 wxLogFatalError( wxT( "Unexpected call to Kiface() in kicad/kicad.cpp" ) );
67
68 throw std::logic_error( "Unexpected call to Kiface() in kicad/kicad.cpp" );
69}
70
71
73
74
76{
77 return program;
78}
79
80
81// Similar to PGM_BASE& Pgm(), but return nullptr when a *.ki_face is run from a python script.
83{
84 return &program;
85}
86
87
89{
90 return program;
91}
92
93
95{
96 App().SetAppDisplayName( wxT( "KiCad" ) );
97
98#if defined(DEBUG)
99 wxString absoluteArgv0 = wxStandardPaths::Get().GetExecutablePath();
100
101 if( !wxIsAbsolutePath( absoluteArgv0 ) )
102 {
103 wxLogError( wxT( "No meaningful argv[0]" ) );
104 return false;
105 }
106#endif
107
108 static const wxCmdLineEntryDesc desc[] = {
109 { wxCMD_LINE_OPTION, "f", "frame", "Frame to load", wxCMD_LINE_VAL_STRING, 0 },
110 { wxCMD_LINE_PARAM, nullptr, nullptr, "File to load", wxCMD_LINE_VAL_STRING,
111 wxCMD_LINE_PARAM_MULTIPLE | wxCMD_LINE_PARAM_OPTIONAL },
112 { wxCMD_LINE_NONE, nullptr, nullptr, nullptr, wxCMD_LINE_VAL_NONE, 0 }
113 };
114
115 wxCmdLineParser parser( App().argc, App().argv );
116 parser.SetDesc( desc );
117 parser.Parse( false );
118
119 FRAME_T appType = KICAD_MAIN_FRAME_T;
120
121 const struct
122 {
123 wxString name;
124 FRAME_T type;
125 } frameTypes[] = { { wxT( "pcb" ), FRAME_PCB_EDITOR },
126 { wxT( "fpedit" ), FRAME_FOOTPRINT_EDITOR },
127 { wxT( "sch" ), FRAME_SCH },
128 { wxT( "calc" ), FRAME_CALC },
129 { wxT( "bm2cmp" ), FRAME_BM2CMP },
130 { wxT( "ds" ), FRAME_PL_EDITOR },
131 { wxT( "gerb" ), FRAME_GERBER },
132 { wxT( "" ), FRAME_T_COUNT } };
133
134 wxString frameName;
135
136 if( parser.Found( "frame", &frameName ) )
137 {
138 appType = FRAME_T_COUNT;
139
140 for( const auto& it : frameTypes )
141 {
142 if( it.name == frameName )
143 appType = it.type;
144 }
145
146 if( appType == FRAME_T_COUNT )
147 {
148 wxLogError( wxT( "Unknown frame: %s" ), frameName );
149 // Clean up
150 OnPgmExit();
151 return false;
152 }
153 }
154
155 if( appType == KICAD_MAIN_FRAME_T )
156 {
158 }
159 else
160 {
162 }
163
164 bool skipPythonInit = false;
165
166 if( appType == FRAME_BM2CMP || appType == FRAME_PL_EDITOR || appType == FRAME_GERBER
167 || appType == FRAME_CALC )
168 skipPythonInit = true;
169
170 if( !InitPgm( false, skipPythonInit ) )
171 return false;
172
176 m_bm.Init();
177
178 // Add search paths to feed the PGM_KICAD::SysSearch() function,
179 // currently limited in support to only look for project templates
180 {
181 SEARCH_STACK bases;
182
183 SystemDirsAppend( &bases );
184
185 for( unsigned i = 0; i < bases.GetCount(); ++i )
186 {
187 wxFileName fn( bases[i], wxEmptyString );
188
189 // Add KiCad template file path to search path list.
190 fn.AppendDir( wxT( "template" ) );
191
192 // Only add path if exists and can be read by the user.
193 if( fn.DirExists() && fn.IsDirReadable() )
194 m_bm.m_search.AddPaths( fn.GetPath() );
195 }
196
197 // The KICAD7_TEMPLATE_DIR takes precedence over the search stack template path.
198 ENV_VAR_MAP_CITER it = GetLocalEnvVariables().find( "KICAD7_TEMPLATE_DIR" );
199
200 if( it != GetLocalEnvVariables().end() && it->second.GetValue() != wxEmptyString )
201 m_bm.m_search.Insert( it->second.GetValue(), 0 );
202
203 // We've been adding system (installed default) search paths so far, now for user paths
204 // The default user search path is inside KIPLATFORM::ENV::GetDocumentsPath()
206
207 // ...but the user can override that default with the KICAD_USER_TEMPLATE_DIR env var
208 it = GetLocalEnvVariables().find( "KICAD_USER_TEMPLATE_DIR" );
209
210 if( it != GetLocalEnvVariables().end() && it->second.GetValue() != wxEmptyString )
211 m_bm.m_search.Insert( it->second.GetValue(), 0 );
212 }
213
214 wxFrame* frame = nullptr;
215 KIWAY_PLAYER* playerFrame = nullptr;
216 KICAD_MANAGER_FRAME* managerFrame = nullptr;
217
218 if( appType == KICAD_MAIN_FRAME_T )
219 {
220 managerFrame = new KICAD_MANAGER_FRAME( nullptr, wxT( "KiCad" ), wxDefaultPosition,
221 wxSize( 775, -1 ) );
222 frame = managerFrame;
223 }
224 else
225 {
226 // Use KIWAY to create a top window, which registers its existence also.
227 // "TOP_FRAME" is a macro that is passed on compiler command line from CMake,
228 // and is one of the types in FRAME_T.
229 playerFrame = Kiway.Player( appType, true );
230 frame = playerFrame;
231
232 if( frame == nullptr )
233 {
234 return false;
235 }
236 }
237
238 App().SetTopWindow( frame );
239
240 if( playerFrame )
241 App().SetAppDisplayName( playerFrame->GetAboutTitle() );
242
243 Kiway.SetTop( frame );
244
245 KICAD_SETTINGS* settings = static_cast<KICAD_SETTINGS*>( PgmSettings() );
246
247 wxString projToLoad;
248
249
250 if( playerFrame && parser.GetParamCount() )
251 {
252 // Now after the frame processing, the rest of the positional args are files
253 std::vector<wxString> fileArgs;
254 /*
255 gerbview handles multiple project data files, i.e. gerber files on
256 cmd line. Others currently do not, they handle only one. For common
257 code simplicity we simply pass all the arguments in however, each
258 program module can do with them what they want, ignore, complain
259 whatever. We don't establish policy here, as this is a multi-purpose
260 launcher.
261 */
262
263 for( size_t i = 0; i < parser.GetParamCount(); i++ )
264 fileArgs.push_back( parser.GetParam( i ) );
265
266 // special attention to a single argument: argv[1] (==argSet[0])
267 if( fileArgs.size() == 1 )
268 {
269 wxFileName argv1( fileArgs[0] );
270
271#if defined( PGM_DATA_FILE_EXT )
272 // PGM_DATA_FILE_EXT, if present, may be different for each compile,
273 // it may come from CMake on the compiler command line, but often does not.
274 // This facility is mostly useful for those program footprints
275 // supporting a single argv[1].
276 if( !argv1.GetExt() )
277 argv1.SetExt( wxT( PGM_DATA_FILE_EXT ) );
278#endif
279 argv1.MakeAbsolute();
280
281 fileArgs[0] = argv1.GetFullPath();
282 }
283
284 // Use the KIWAY_PLAYER::OpenProjectFiles() API function:
285 if( !playerFrame->OpenProjectFiles( fileArgs ) )
286 {
287 // OpenProjectFiles() API asks that it report failure to the UI.
288 // Nothing further to say here.
289
290 // We've already initialized things at this point, but wx won't call OnExit if
291 // we fail out. Call our own cleanup routine here to ensure the relevant resources
292 // are freed at the right time (if they aren't, segfaults will occur).
293 OnPgmExit();
294
295 // Fail the process startup if the file could not be opened,
296 // although this is an optional choice, one that can be reversed
297 // also in the KIFACE specific OpenProjectFiles() return value.
298 return false;
299 }
300 }
301 else if( managerFrame )
302 {
303 if( App().argc > 1 )
304 {
305 wxFileName tmp = App().argv[1];
306
307 if( tmp.GetExt() != ProjectFileExtension && tmp.GetExt() != LegacyProjectFileExtension )
308 {
309 wxString msg;
310
311 msg.Printf( _( "File '%s'\ndoes not appear to be a valid KiCad project file." ),
312 tmp.GetFullPath() );
313 wxMessageDialog dlg( nullptr, msg, _( "Error" ), wxOK | wxICON_EXCLAMATION );
314 dlg.ShowModal();
315 }
316 else
317 {
318 projToLoad = tmp.GetFullPath();
319 }
320 }
321
322 // If no file was given as an argument, check that there was a file open.
323 if( projToLoad.IsEmpty() && settings->m_OpenProjects.size() )
324 {
325 wxString last_pro = settings->m_OpenProjects.front();
326 settings->m_OpenProjects.erase( settings->m_OpenProjects.begin() );
327
328 if( wxFileExists( last_pro ) )
329 {
330 // Try to open the last opened project,
331 // if a project name is not given when starting Kicad
332 projToLoad = last_pro;
333 }
334 }
335
336 // Do not attempt to load a non-existent project file.
337 if( !projToLoad.empty() )
338 {
339 wxFileName fn( projToLoad );
340
341 if( fn.Exists() )
342 {
343 fn.MakeAbsolute();
344
345 if( appType == KICAD_MAIN_FRAME_T )
346 {
347 managerFrame->LoadProject( fn );
348 }
349 }
350 }
351 }
352
353 frame->Show( true );
354 frame->Raise();
355
356 return true;
357}
358
359
361{
362 return 0;
363}
364
365
367{
369
371 {
373 m_settings_manager->Save();
374 }
375
376 // Destroy everything in PGM_KICAD,
377 // especially wxSingleInstanceCheckerImpl earlier than wxApp and earlier
378 // than static destruction would.
379 Destroy();
380}
381
382
383void PGM_KICAD::MacOpenFile( const wxString& aFileName )
384{
385#if defined(__WXMAC__)
386
387 KICAD_MANAGER_FRAME* frame = (KICAD_MANAGER_FRAME*) App().GetTopWindow();
388
389 if( !aFileName.empty() && wxFileExists( aFileName ) )
390 frame->LoadProject( wxFileName( aFileName ) );
391
392#endif
393}
394
395
397{
398 // unlike a normal destructor, this is designed to be called more
399 // than once safely:
400
401 m_bm.End();
402
404}
405
406
408
409
410// Define a custom assertion handler
411void CustomAssertHandler(const wxString& file,
412 int line,
413 const wxString& func,
414 const wxString& cond,
415 const wxString& msg)
416{
417 Pgm().HandleAssert( file, line, func, cond, msg );
418}
419
423struct APP_KICAD : public wxApp
424{
425 APP_KICAD() : wxApp()
426 {
427 // Init the environment each platform wants
429 }
430
431
432 bool OnInit() override
433 {
434 wxDISABLE_DEBUG_SUPPORT();
435 wxSetAssertHandler( CustomAssertHandler );
436
437 // Perform platform-specific init tasks
438 if( !KIPLATFORM::APP::Init() )
439 return false;
440
441 if( !program.OnPgmInit() )
442 {
444 return false;
445 }
446
447 return true;
448 }
449
450 int OnExit() override
451 {
453
454 // Avoid wxLog crashing when used in destructors.
455 wxLog::EnableLogging( false );
456
457 return wxApp::OnExit();
458 }
459
460 int OnRun() override
461 {
462 try
463 {
464 return wxApp::OnRun();
465 }
466 catch(...)
467 {
468 Pgm().HandleException( std::current_exception() );
469 }
470
471 return -1;
472 }
473
474 int FilterEvent( wxEvent& aEvent ) override
475 {
476 if( aEvent.GetEventType() == wxEVT_SHOW )
477 {
478 wxShowEvent& event = static_cast<wxShowEvent&>( aEvent );
479 wxDialog* dialog = dynamic_cast<wxDialog*>( event.GetEventObject() );
480
481 std::vector<void*>& dlgs = Pgm().m_ModalDialogs;
482
483 if( dialog )
484 {
485 if( event.IsShown() && dialog->IsModal() )
486 {
487 dlgs.push_back( dialog );
488 }
489 // Under GTK, sometimes the modal flag is cleared before hiding
490 else if( !event.IsShown() && !dlgs.empty() )
491 {
492 // If we close the expected dialog, remove it from our stack
493 if( dlgs.back() == dialog )
494 dlgs.pop_back();
495 // If an out-of-order, remove all dialogs added after the closed one
496 else if( auto it = std::find( dlgs.begin(), dlgs.end(), dialog ) ; it != dlgs.end() )
497 dlgs.erase( it, dlgs.end() );
498 }
499 }
500 }
501
502 return Event_Skip;
503 }
504
505#if defined( DEBUG )
509 bool ProcessEvent( wxEvent& aEvent ) override
510 {
511 if( aEvent.GetEventType() == wxEVT_CHAR || aEvent.GetEventType() == wxEVT_CHAR_HOOK )
512 {
513 wxKeyEvent* keyEvent = static_cast<wxKeyEvent*>( &aEvent );
514
515 if( keyEvent )
516 {
517 wxLogTrace( kicadTraceKeyEvent, "APP_KICAD::ProcessEvent %s", dump( *keyEvent ) );
518 }
519 }
520
521 aEvent.Skip();
522 return false;
523 }
524
532 bool OnExceptionInMainLoop() override
533 {
534 try
535 {
536 throw;
537 }
538 catch(...)
539 {
540 Pgm().HandleException( std::current_exception() );
541 }
542
543 return false; // continue on. Return false to abort program
544 }
545#endif
546
552#if defined( __WXMAC__ )
553 void MacOpenFile( const wxString& aFileName ) override
554 {
555 Pgm().MacOpenFile( aFileName );
556 }
557#endif
558};
559
560IMPLEMENT_APP( APP_KICAD )
561
562
563// The C++ project manager supports one open PROJECT, so Prj() calls within
564// this link image need this function.
566{
567 return Kiway.Prj();
568}
569
const char * name
Definition: DXF_plotter.cpp:56
const wxString & GetAboutTitle() const
The main KiCad project manager frame.
void LoadProject(const wxFileName &aProjectFileName)
std::vector< wxString > m_OpenProjects
A KIFACE implementation.
Definition: kiface_base.h:39
A wxFrame capable of the OpenProjectFiles function, meaning it can load a portion of a KiCad project.
Definition: kiway_player.h:66
virtual bool OpenProjectFiles(const std::vector< wxString > &aFileList, int aCtl=0)
Open a project or set of files given by aFileList.
Definition: kiway_player.h:118
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
Definition: kiway.h:279
virtual KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=nullptr)
Return the KIWAY_PLAYER* given a FRAME_T.
Definition: kiway.cpp:432
void SetCtlBits(int aCtlBits)
Overwrites previously set ctl bits, only for use in kicad.cpp to flip between standalone and manager ...
Definition: kiway.h:407
void OnKiwayEnd()
Definition: kiway.cpp:748
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:88
virtual PROJECT & Prj() const
Return the PROJECT associated with this KIWAY.
Definition: kiway.cpp:196
static wxString GetUserTemplatesPath()
Gets the user path for custom templates.
Definition: paths.cpp:86
Container for data for KiCad programs.
Definition: pgm_base.h:96
virtual wxApp & App()
Returns a bare naked wxApp which may come from wxPython, SINGLE_TOP, or kicad.exe.
Definition: pgm_base.cpp:167
virtual ENV_VAR_MAP & GetLocalEnvVariables() const
Definition: pgm_base.cpp:862
virtual void MacOpenFile(const wxString &aFileName)=0
Specific to MacOSX (not used under Linux or Windows).
std::unique_ptr< SETTINGS_MANAGER > m_settings_manager
Definition: pgm_base.h:385
void Destroy()
Definition: pgm_base.cpp:153
bool InitPgm(bool aHeadless=false, bool aSkipPyInit=false, bool aIsUnitTest=false)
Initialize this program.
Definition: pgm_base.cpp:402
std::vector< void * > m_ModalDialogs
Definition: pgm_base.h:360
void HandleException(std::exception_ptr aPtr)
A exception handler to be used at the top level if exceptions bubble up that for.
Definition: pgm_base.cpp:886
void HandleAssert(const wxString &aFile, int aLine, const wxString &aFunc, const wxString &aCond, const wxString &aMsg)
A common assert handler to be used between single_top and kicad.
Definition: pgm_base.cpp:921
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition: pgm_base.h:136
void SaveCommonSettings()
Save the program (process) settings subset which are stored .kicad_common.
Definition: pgm_base.cpp:612
PGM_KICAD extends PGM_BASE to bring in FileHistory() and PdfBrowser() which were moved from EDA_APP i...
Definition: pgm_kicad.h:38
bool OnPgmInit()
Definition: kicad.cpp:94
void Destroy()
Definition: kicad.cpp:396
void MacOpenFile(const wxString &aFileName) override
Specific to MacOSX (not used under Linux or Windows).
Definition: kicad.cpp:383
void OnPgmExit()
Definition: kicad.cpp:366
APP_SETTINGS_BASE * PgmSettings()
Definition: pgm_kicad.h:55
int OnPgmRun()
Definition: kicad.cpp:360
BIN_MOD m_bm
Definition: pgm_kicad.h:68
Container for project specific data.
Definition: project.h:64
Look for files in a number of paths.
Definition: search_stack.h:42
void AddPaths(const wxString &aPaths, int aIndex=-1)
Insert or append path(s).
T * RegisterSettings(T *aSettings, bool aLoadNow=true)
Takes ownership of the pointer passed in.
void SetKiway(KIWAY *aKiway)
Associate this setting manager with the given Kiway.
#define _(s)
FRAME_T
The set of EDA_BASE_FRAME derivatives, typically stored in EDA_BASE_FRAME::m_Ident.
Definition: frame_type.h:33
@ FRAME_PCB_EDITOR
Definition: frame_type.h:40
@ FRAME_CALC
Definition: frame_type.h:59
@ FRAME_BM2CMP
Definition: frame_type.h:57
@ FRAME_SCH
Definition: frame_type.h:34
@ FRAME_T_COUNT
Definition: frame_type.h:66
@ FRAME_PL_EDITOR
Definition: frame_type.h:55
@ FRAME_FOOTPRINT_EDITOR
Definition: frame_type.h:41
@ FRAME_GERBER
Definition: frame_type.h:53
@ KICAD_MAIN_FRAME_T
Definition: frame_type.h:64
const std::string LegacyProjectFileExtension
const std::string ProjectFileExtension
const wxChar *const kicadTraceKeyEvent
Flag to enable wxKeyEvent debug tracing.
std::map< wxString, ENV_VAR_ITEM >::const_iterator ENV_VAR_MAP_CITER
void CustomAssertHandler(const wxString &file, int line, const wxString &func, const wxString &cond, const wxString &msg)
Definition: kicad.cpp:411
PGM_KICAD & PgmTop()
Definition: kicad.cpp:88
PROJECT & Prj()
Definition: kicad.cpp:565
static PGM_KICAD program
Definition: kicad.cpp:72
PGM_BASE & Pgm()
The global Program "get" accessor.
Definition: kicad.cpp:75
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
Definition: kicad.cpp:61
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:82
#define KFCTL_CPP_PROJECT_SUITE
Running under C++ project mgr, possibly with others.
Definition: kiway.h:159
KIWAY Kiway
#define KFCTL_STANDALONE
Running as a standalone Top.
Definition: kiway.h:158
This file contains miscellaneous commonly used macros and functions.
bool Init()
Perform application-specific initialization tasks.
Definition: gtk/app.cpp:40
void Init()
Perform environment initialization tasks.
Not publicly visible because most of the action is in PGM_KICAD these days.
Definition: kicad.cpp:424
int OnRun() override
Definition: kicad.cpp:460
APP_KICAD()
Definition: kicad.cpp:425
bool OnInit() override
Definition: kicad.cpp:432
int OnExit() override
Definition: kicad.cpp:450
int FilterEvent(wxEvent &aEvent) override
Definition: kicad.cpp:474
void End()
Definition: bin_mod.cpp:50
void Init()
Definition: bin_mod.cpp:38
SEARCH_STACK m_search
Definition: bin_mod.h:60
void InitSettings(APP_SETTINGS_BASE *aPtr)
Takes ownership of a new application settings object.
Definition: bin_mod.h:53
void SystemDirsAppend(SEARCH_STACK *aSearchStack)
Append system places to aSearchStack in a platform specific way and pertinent to KiCad programs.
System directories search utilities.
wxString dump(const wxArrayString &aArray)
Debug helper for printing wxArrayString contents.
wxLogTrace helper definitions.
Definition of file extensions used in Kicad.