KiCad PCB EDA Suite
Loading...
Searching...
No Matches
single_top.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) 2014 SoftPLC Corporation, Dick Hollenbeck <[email protected]>
5 * Copyright The 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
25
26/*
27
28 This is a program launcher for a single KIFACE DSO. It only mimics a KIWAY,
29 not actually implements one, since only a single DSO is supported by it.
30
31 It is compiled multiple times, once for each standalone program and as such
32 gets different compiler command line supplied #defines from CMake.
33
34*/
35
36
37#include <typeinfo>
38#include <wx/cmdline.h>
39#include <wx/dialog.h>
40#include <wx/filename.h>
41#include <wx/stdpaths.h>
42#include <wx/snglinst.h>
43#include <wx/html/htmlwin.h>
44
45#include <kiway.h>
46#include <build_version.h>
47#include <pgm_base.h>
48#include <kiway_player.h>
49#include <macros.h>
50#include <confirm.h>
52
55#include <paths.h>
56
57#include <kiplatform/app.h>
59
60#include <git2.h>
61#include <thread_pool.h>
62
65
66#ifdef KICAD_USE_SENTRY
67#include <sentry.h>
68#endif
69
70#ifdef KICAD_IPC_API
71#include <api/api_server.h>
72#endif
73
74// Only a single KIWAY is supported in this single_top top level component,
75// which is dedicated to loading only a single DSO.
77
78
79// implement a PGM_BASE and a wxApp side by side:
80
84static struct PGM_SINGLE_TOP : public PGM_BASE
85{
86 bool OnPgmInit();
87
88 void OnPgmExit()
89 {
90 // Abort and wait on any background jobs
91 GetKiCadThreadPool().purge();
92 GetKiCadThreadPool().wait();
93
94 Kiway.OnKiwayEnd();
95
96#ifdef KICAD_IPC_API
97 m_api_server.reset();
98#endif
99
101 {
103 m_settings_manager->Save();
104 }
105
106 // Destroy everything in PGM_BASE, especially wxSingleInstanceCheckerImpl
107 // earlier than wxApp and earlier than static destruction would.
109 git_libgit2_shutdown();
110 }
111
112 void MacOpenFile( const wxString& aFileName ) override
113 {
114 wxFileName filename( aFileName );
115
116 if( filename.FileExists() )
117 {
118 #if 0
119 // this pulls in EDA_DRAW_FRAME type info, which we don't want in
120 // the single_top link image.
121 KIWAY_PLAYER* frame = dynamic_cast<KIWAY_PLAYER*>( App().GetTopWindow() );
122 #else
123 KIWAY_PLAYER* frame = (KIWAY_PLAYER*) App().GetTopWindow();
124 #endif
125 if( frame )
126 {
127 if( wxWindow* blocking_win = frame->Kiway().GetBlockingDialog() )
128 blocking_win->Close( true );
129
130 frame->OpenProjectFiles( std::vector<wxString>( 1, aFileName ) );
131 }
132 }
133 }
134
136
137
138// A module to allow Html module initialization/cleanup
139// When a wxHtmlWindow is used *only* in a dll/so module, the Html text is displayed
140// as plain text.
141// This helper class is just used to force wxHtmlWinParser initialization
142// see https://groups.google.com/forum/#!topic/wx-users/FF0zv5qGAT0
143class HtmlModule: public wxModule
144{
145public:
147 virtual bool OnInit() override { AddDependency( CLASSINFO( wxHtmlWinParser ) ); return true; };
148 virtual void OnExit() override {};
149
150private:
152};
153
155
156
157#ifdef NDEBUG
158// Define a custom assertion handler
159void CustomAssertHandler( const wxString& file,
160 int line,
161 const wxString& func,
162 const wxString& cond,
163 const wxString& msg )
164{
165 Pgm().HandleAssert( file, line, func, cond, msg );
166}
167#endif
168
169
174struct APP_SINGLE_TOP : public wxApp
175{
176 APP_SINGLE_TOP() : wxApp()
177 {
178 SetPgm( &program );
179
180 // Init the environment each platform wants
182 }
183
184
185 bool OnInit() override
186 {
187#ifdef NDEBUG
188 // These checks generate extra assert noise
189 wxSizerFlags::DisableConsistencyChecks();
190 wxDISABLE_DEBUG_SUPPORT();
191 wxSetAssertHandler( CustomAssertHandler );
192#endif
193
194 // Perform platform-specific init tasks
195 if( !KIPLATFORM::APP::Init() )
196 return false;
197
198#ifndef DEBUG
199 // Enable logging traces to the console in release build.
200 // This is usually disabled, but it can be useful for users to run to help
201 // debug issues and other problems.
202 if( wxGetEnv( wxS( "KICAD_ENABLE_WXTRACE" ), nullptr ) )
203 {
204 wxLog::EnableLogging( true );
205 wxLog::SetLogLevel( wxLOG_Trace );
206 }
207#endif
208
209 // Force wxHtmlWinParser initialization when a wxHtmlWindow is used only
210 // in a shared library (.so or .dll file)
211 // Otherwise the Html text is displayed as plain text.
212 HtmlModule html_init;
213
214 try
215 {
216 return program.OnPgmInit();
217 }
218 catch( ... )
219 {
220 Pgm().HandleException( std::current_exception() );
221 }
222
223 program.OnPgmExit();
224
225 return false;
226 }
227
228 int OnExit() override
229 {
230 program.OnPgmExit();
231 return wxApp::OnExit();
232 }
233
234 int OnRun() override
235 {
236 int ret = -1;
237
238 try
239 {
240 ret = wxApp::OnRun();
241 }
242 catch(...)
243 {
244 Pgm().HandleException( std::current_exception() );
245 }
246
247 return ret;
248 }
249
250 int FilterEvent( wxEvent& aEvent ) override
251 {
252 if( aEvent.GetEventType() == wxEVT_SHOW )
253 {
254 wxShowEvent& event = static_cast<wxShowEvent&>( aEvent );
255 wxDialog* dialog = dynamic_cast<wxDialog*>( event.GetEventObject() );
256
257 std::vector<void*>& dlgs = Pgm().m_ModalDialogs;
258
259 if( dialog )
260 {
261 if( event.IsShown() && dialog->IsModal() )
262 {
263 dlgs.push_back( dialog );
264 }
265 // Under GTK, sometimes the modal flag is cleared before hiding
266 else if( !event.IsShown() && !dlgs.empty() )
267 {
268 // If we close the expected dialog, remove it from our stack
269 if( dlgs.back() == dialog )
270 dlgs.pop_back();
271 // If an out-of-order, remove all dialogs added after the closed one
272 else if( auto it = std::find( dlgs.begin(), dlgs.end(), dialog ); it != dlgs.end() )
273 dlgs.erase( it, dlgs.end() );
274 }
275 }
276 }
277
278 return Event_Skip;
279 }
280
281#if defined( DEBUG )
289 virtual bool OnExceptionInMainLoop() override
290 {
291 try
292 {
293 throw;
294 }
295 catch( ... )
296 {
297 Pgm().HandleException( std::current_exception() );
298 }
299
300 return false; // continue on. Return false to abort program
301 }
302#endif
303
304#ifdef __WXMAC__
305
313 void MacOpenFile( const wxString& aFileName ) override
314 {
315 Pgm().MacOpenFile( aFileName );
316 }
317
318#endif
319};
320
321IMPLEMENT_APP( APP_SINGLE_TOP )
322
323
325{
326#if defined(DEBUG)
327 wxString absoluteArgv0 = wxStandardPaths::Get().GetExecutablePath();
328
329 if( !wxIsAbsolutePath( absoluteArgv0 ) )
330 {
331 wxLogError( wxT( "No meaningful argv[0]" ) );
332 return false;
333 }
334#endif
335
336 // Initialize the git library before trying to initialize individual programs
337 int gitInit = git_libgit2_init();
338
339 if( gitInit < 0 )
340 {
341 const git_error* err = git_error_last();
342 wxString msg = wxS( "Failed to initialize git library" );
343
344 if( err && err->message )
345 msg += wxS( ": " ) + wxString::FromUTF8( err->message );
346
347 wxLogError( msg );
348 return false;
349 }
350
351 // Not all KiCad applications use the python stuff. skip python init
352 // for these apps.
353 bool skip_python_initialization = false;
354
355#if defined( BITMAP_2_CMP ) || defined( PL_EDITOR ) || defined( GERBVIEW ) || \
356 defined( PCB_CALCULATOR_BUILD )
357 skip_python_initialization = true;
358#endif
359
360 if( !InitPgm( false, skip_python_initialization ) )
361 {
362 // Clean up
363 OnPgmExit();
364 return false;
365 }
366
367#if !defined(BUILD_KIWAY_DLL)
368
369 // Only bitmap2component and pcb_calculator use this code currently, as they
370 // are not split to use single_top as a link image separate from a *.kiface.
371 // i.e. they are single part link images so don't need to load a *.kiface.
372
373 // Get the getter, it is statically linked into this binary image.
374 KIFACE_GETTER_FUNC* ki_getter = &KIFACE_GETTER;
375
376 int kiface_version;
377
378 // Get the KIFACE.
379 KIFACE* kiface = ki_getter( &kiface_version, KIFACE_VERSION, this );
380
381 // Trick the KIWAY into thinking it loaded a KIFACE, by recording the KIFACE
382 // in the KIWAY. It needs to be there for KIWAY::OnKiwayEnd() anyways.
383 Kiway.set_kiface( KIWAY::KifaceType( TOP_FRAME ), kiface );
384#endif
385
386 // Tell the settings manager about the current Kiway
388
390
391#ifdef KICAD_IPC_API
392 // Create the API server thread once the app event loop exists
393 m_api_server = std::make_unique<KICAD_API_SERVER>();
394#endif
395
396 // Use KIWAY to create a top window, which registers its existence also.
397 // "TOP_FRAME" is a macro that is passed on compiler command line from CMake,
398 // and is one of the types in FRAME_T.
399 KIWAY_PLAYER* frame = Kiway.Player( TOP_FRAME, true );
400
401 if( frame == nullptr )
402 {
403 // Clean up
404 OnPgmExit();
405 return false;
406 }
407
408 Kiway.SetTop( frame );
409
410 STARTWIZARD startWizard;
411 startWizard.CheckAndRun( frame );
412
413 // Load library tables after startup wizard
414 GetLibraryManager().LoadGlobalTables();
415
416 // Preload libraries, since for single-top this won't have been done earlier
417 if( KIFACE* topFrame = Kiway.KiFACE( KIWAY::KifaceType( TOP_FRAME ) ) )
418 topFrame->PreloadLibraries( &Kiway );
419
421
422 App().SetTopWindow( frame ); // wxApp gets a face.
423 App().SetAppDisplayName( frame->GetAboutTitle() );
424
425 wxString relaunchDisplayName = frame->GetAboutTitle() + " " + GetMajorMinorVersion();
427
428 // Allocate a slice of time to show the frame and update wxWidgets widgets
429 // (especially setting valid sizes) after creating frame and before calling
430 // OpenProjectFiles() that can update/use some widgets.
431 // The 2 calls to wxSafeYield are needed on wxGTK for best results.
432 wxSafeYield();
433 HideSplash();
434 frame->Show();
435 wxSafeYield();
436
437 // Now after the frame processing, the rest of the positional args are files
438 std::vector<wxString> fileArgs;
439
440
441 static const wxCmdLineEntryDesc desc[] = {
442 { wxCMD_LINE_PARAM, nullptr, nullptr, "File to load", wxCMD_LINE_VAL_STRING,
443 wxCMD_LINE_PARAM_MULTIPLE | wxCMD_LINE_PARAM_OPTIONAL },
444 { wxCMD_LINE_NONE, nullptr, nullptr, nullptr, wxCMD_LINE_VAL_NONE, 0 }
445 };
446
447 wxCmdLineParser parser( App().argc, App().argv );
448 parser.SetDesc( desc );
449 parser.Parse( false );
450
451 if( parser.GetParamCount() )
452 {
453 /*
454 gerbview handles multiple project data files, i.e. gerber files on
455 cmd line. Others currently do not, they handle only one. For common
456 code simplicity we simply pass all the arguments in however, each
457 program module can do with them what they want, ignore, complain
458 whatever. We don't establish policy here, as this is a multi-purpose
459 launcher.
460 */
461
462 for( size_t i = 0; i < parser.GetParamCount(); i++ )
463 fileArgs.push_back( parser.GetParam( i ) );
464
465 // special attention to a single argument: argv[1] (==argSet[0])
466 if( fileArgs.size() == 1 )
467 {
468 wxFileName argv1( fileArgs[0] );
469
470#if defined(PGM_DATA_FILE_EXT)
471 // PGM_DATA_FILE_EXT, if present, may be different for each compile,
472 // it may come from CMake on the compiler command line, but often does not.
473 // This facility is mostly useful for those program footprints
474 // supporting a single argv[1].
475 if( !argv1.GetExt() )
476 argv1.SetExt( wxT( PGM_DATA_FILE_EXT ) );
477#endif
478 argv1.MakeAbsolute();
479
480 fileArgs[0] = argv1.GetFullPath();
481 }
482
483 frame->OpenProjectFiles( fileArgs );
484 }
485
486#ifdef KICAD_IPC_API
487 m_api_server->SetReadyToReply();
488#endif
489
490 return true;
491}
wxString GetMajorMinorVersion()
Get only the major and minor version in a string major.minor.
const wxString & GetAboutTitle() const
virtual bool OnInit() override
virtual void OnExit() override
wxDECLARE_DYNAMIC_CLASS(HtmlModule)
KIWAY & Kiway() const
Return a reference to the KIWAY that this object has an opportunity to participate in.
A wxFrame capable of the OpenProjectFiles function, meaning it can load a portion of a KiCad project.
virtual bool OpenProjectFiles(const std::vector< wxString > &aFileList, int aCtl=0)
Open a project or set of files given by aFileList.
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
Definition kiway.h:292
static FACE_T KifaceType(FRAME_T aFrameType)
A simple mapping function which returns the FACE_T which is known to implement aFrameType.
Definition kiway.cpp:341
wxWindow * GetBlockingDialog()
Gets the window pointer to the blocking dialog (to send it signals)
Definition kiway.cpp:680
static const wxString & GetExecutablePath()
Definition paths.cpp:629
virtual wxApp & App()
Return a bare naked wxApp which may come from wxPython, SINGLE_TOP, or kicad.exe.
Definition pgm_base.cpp:192
void PreloadDesignBlockLibraries(KIWAY *aKiway)
Starts a background job to preload the global and project design block libraries.
Definition pgm_base.cpp:871
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:387
void Destroy()
Definition pgm_base.cpp:178
bool InitPgm(bool aHeadless=false, bool aSkipPyInit=false, bool aIsUnitTest=false)
Initialize this program.
Definition pgm_base.cpp:308
std::vector< void * > m_ModalDialogs
Definition pgm_base.h:368
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:798
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:823
void HideSplash()
Definition pgm_base.cpp:297
virtual LIBRARY_MANAGER & GetLibraryManager() const
Definition pgm_base.h:131
void SaveCommonSettings()
Save the program (process) settings subset which are stored .kicad_common.
Definition pgm_base.cpp:528
T * RegisterSettings(T *aSettings, bool aLoadNow=true)
Take ownership of the pointer passed in.
void SetKiway(KIWAY *aKiway)
Associate this setting manager with the given Kiway.
void CheckAndRun(wxWindow *parent)
This file is part of the common library.
KIFACE * KIFACE_GETTER_FUNC(int *aKIFACEversion, int aKIWAYversion, PGM_BASE *aProgram)
Point to the one and only KIFACE export.
Definition kiway.h:527
#define KIFACE_GETTER
Definition kiway.h:110
#define KIFACE_VERSION
The KIWAY and KIFACE classes are used to communicate between various process modules,...
Definition kiway.h:109
#define KFCTL_STANDALONE
Running as a standalone Top.
Definition kiway.h:162
This file contains miscellaneous commonly used macros and functions.
bool Init()
Perform application-specific initialization tasks.
Definition unix/app.cpp:40
void Init()
Perform environment initialization tasks.
void SetAppDetailsForWindow(wxWindow *aWindow, const wxString &aRelaunchCommand, const wxString &aRelaunchDisplayName)
Sets the relaunch command for taskbar pins, this is intended for Windows.
SETTINGS_MANAGER * GetSettingsManager()
void SetPgm(PGM_BASE *pgm)
Definition pgm_base.cpp:960
PGM_BASE & Pgm()
The global program "get" accessor.
Definition pgm_base.cpp:946
see class PGM_BASE
PGM_SINGLE_TOP program
wxIMPLEMENT_DYNAMIC_CLASS(HtmlModule, wxModule)
KIWAY Kiway(KFCTL_STANDALONE)
Implement a bare naked wxApp (so that we don't become dependent on functionality in a wxApp derivativ...
int OnRun() override
int OnExit() override
bool OnInit() override
int FilterEvent(wxEvent &aEvent) override
Implement a participant in the KIWAY alchemy.
Definition kiway.h:155
Implement PGM_BASE with its own OnPgmInit() and OnPgmExit().
void MacOpenFile(const wxString &aFileName) override
Specific to MacOSX (not used under Linux or Windows).
IFACE KIFACE_BASE kiface("pcb_test_frame", KIWAY::FACE_PCB)
thread_pool & GetKiCadThreadPool()
Get a reference to the current thread pool.