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 <app_monitor.h>
49#include <kiway_player.h>
50#include <macros.h>
51#include <confirm.h>
53
57#include <paths.h>
58
59#include <kiplatform/app.h>
61
62#include <git2.h>
63#include <git/git_backend.h>
64#include <git/libgit_backend.h>
65#include <thread_pool.h>
66
69
70#ifdef KICAD_USE_SENTRY
71#include <sentry.h>
72#endif
73
74#ifdef KICAD_IPC_API
75#include <api/api_server.h>
76#endif
77
78// Only a single KIWAY is supported in this single_top top level component,
79// which is dedicated to loading only a single DSO.
81
82
83// implement a PGM_BASE and a wxApp side by side:
84
88static struct PGM_SINGLE_TOP : public PGM_BASE
89{
90 bool OnPgmInit();
91
92 void OnPgmExit()
93 {
94 // Abort and wait on any background jobs
95 GetKiCadThreadPool().purge();
96 GetKiCadThreadPool().wait();
97
98 Kiway.OnKiwayEnd();
99
100#ifdef KICAD_IPC_API
101 m_api_server.reset();
102#endif
103
105 {
107 m_settings_manager->Save();
108 }
109
110 // Destroy everything in PGM_BASE, especially wxSingleInstanceCheckerImpl
111 // earlier than wxApp and earlier than static destruction would.
113
114 if( GIT_BACKEND* backend = GetGitBackend() )
115 {
116 backend->Shutdown();
117 delete backend;
118 SetGitBackend( nullptr );
119 }
120 }
121
122 void MacOpenFile( const wxString& aFileName ) override
123 {
124 wxFileName filename( aFileName );
125
126 if( filename.FileExists() )
127 {
128 #if 0
129 // this pulls in EDA_DRAW_FRAME type info, which we don't want in
130 // the single_top link image.
131 KIWAY_PLAYER* frame = dynamic_cast<KIWAY_PLAYER*>( App().GetTopWindow() );
132 #else
133 KIWAY_PLAYER* frame = (KIWAY_PLAYER*) App().GetTopWindow();
134 #endif
135 if( frame )
136 {
137 if( wxWindow* blocking_win = frame->Kiway().GetBlockingDialog() )
138 blocking_win->Close( true );
139
140 frame->OpenProjectFiles( std::vector<wxString>( 1, aFileName ) );
141 }
142 }
143 }
144
146
147
148// A module to allow Html module initialization/cleanup
149// When a wxHtmlWindow is used *only* in a dll/so module, the Html text is displayed
150// as plain text.
151// This helper class is just used to force wxHtmlWinParser initialization
152// see https://groups.google.com/forum/#!topic/wx-users/FF0zv5qGAT0
153class HtmlModule: public wxModule
154{
155public:
157 virtual bool OnInit() override { AddDependency( CLASSINFO( wxHtmlWinParser ) ); return true; };
158 virtual void OnExit() override {};
159
160private:
162};
163
165
166
167#ifdef NDEBUG
168// Define a custom assertion handler
169void CustomAssertHandler( const wxString& file,
170 int line,
171 const wxString& func,
172 const wxString& cond,
173 const wxString& msg )
174{
175 Pgm().HandleAssert( file, line, func, cond, msg );
176}
177#endif
178
179
184struct APP_SINGLE_TOP : public wxApp
185{
186 APP_SINGLE_TOP() : wxApp()
187 {
188 SetPgm( &program );
189
190 // Init the environment each platform wants
192 }
193
194
195 bool OnInit() override
196 {
197#ifdef NDEBUG
198 // These checks generate extra assert noise
199 wxSizerFlags::DisableConsistencyChecks();
200 wxDISABLE_DEBUG_SUPPORT();
201 wxSetAssertHandler( CustomAssertHandler );
202#endif
203
204 // Perform platform-specific init tasks
205 if( !KIPLATFORM::APP::Init() )
206 return false;
207
208#ifndef DEBUG
209 // Enable logging traces to the console in release build.
210 // This is usually disabled, but it can be useful for users to run to help
211 // debug issues and other problems.
212 if( wxGetEnv( wxS( "KICAD_ENABLE_WXTRACE" ), nullptr ) )
213 {
214 wxLog::EnableLogging( true );
215 wxLog::SetLogLevel( wxLOG_Trace );
216 }
217#endif
218
219 // Force wxHtmlWinParser initialization when a wxHtmlWindow is used only
220 // in a shared library (.so or .dll file)
221 // Otherwise the Html text is displayed as plain text.
222 HtmlModule html_init;
223
224 try
225 {
226 return program.OnPgmInit();
227 }
228 catch( ... )
229 {
230 Pgm().HandleException( std::current_exception() );
231 }
232
233 program.OnPgmExit();
234
235 return false;
236 }
237
238 int OnExit() override
239 {
240 // Drain wxPendingDelete (frames deferred via Destroy()) before tearing down
241 // PGM_BASE singletons. On macOS the dock-quit path leaves frames in this
242 // queue at OnExit() time, and their canvas destructors call into
243 // Pgm().GetGLContextManager(). Running OnPgmExit() first would null that
244 // pointer out from under them. See https://gitlab.com/kicad/code/kicad/-/issues/23373
245 int ret = wxApp::OnExit();
246 program.OnPgmExit();
247 return ret;
248 }
249
250 int OnRun() override
251 {
252 int ret = -1;
253
254 try
255 {
256 ret = wxApp::OnRun();
257 }
258 catch(...)
259 {
260 Pgm().HandleException( std::current_exception() );
261 }
262
263 return ret;
264 }
265
266 int FilterEvent( wxEvent& aEvent ) override
267 {
268 if( aEvent.GetEventType() == wxEVT_SHOW )
269 {
270 wxShowEvent& event = static_cast<wxShowEvent&>( aEvent );
271 wxDialog* dialog = dynamic_cast<wxDialog*>( event.GetEventObject() );
272
273 std::vector<void*>& dlgs = Pgm().m_ModalDialogs;
274
275 if( dialog )
276 {
277 if( event.IsShown() && dialog->IsModal() )
278 {
279 dlgs.push_back( dialog );
280 }
281 // Under GTK, sometimes the modal flag is cleared before hiding
282 else if( !event.IsShown() && !dlgs.empty() )
283 {
284 // If we close the expected dialog, remove it from our stack
285 if( dlgs.back() == dialog )
286 dlgs.pop_back();
287 // If an out-of-order, remove all dialogs added after the closed one
288 else if( auto it = std::find( dlgs.begin(), dlgs.end(), dialog ); it != dlgs.end() )
289 dlgs.erase( it, dlgs.end() );
290 }
291 }
292 }
293
294 return Event_Skip;
295 }
296
297 void OnUnhandledException() override
298 {
299 Pgm().HandleException( std::current_exception(), true );
300 }
301
302#if defined( DEBUG )
310 virtual bool OnExceptionInMainLoop() override
311 {
312 try
313 {
314 throw;
315 }
316 catch( ... )
317 {
318 Pgm().HandleException( std::current_exception() );
319 }
320
321 return false; // continue on. Return false to abort program
322 }
323#endif
324
325#ifdef __WXMAC__
326
334 void MacOpenFile( const wxString& aFileName ) override
335 {
336 Pgm().MacOpenFile( aFileName );
337 }
338
339#endif
340};
341
342IMPLEMENT_APP( APP_SINGLE_TOP )
343
344
346{
347#if defined(DEBUG)
348 wxString absoluteArgv0 = wxStandardPaths::Get().GetExecutablePath();
349
350 if( !wxIsAbsolutePath( absoluteArgv0 ) )
351 {
352 wxLogError( wxT( "No meaningful argv[0]" ) );
353 return false;
354 }
355#endif
356
357 // Initialize the git backend before trying to initialize individual programs
359 GetGitBackend()->Init();
360
361 if( !GetGitBackend()->IsLibraryAvailable() )
362 {
363 const git_error* err = git_error_last();
364 wxString msg = wxS( "Failed to initialize git library" );
365
366 if( err && err->message )
367 msg += wxS( ": " ) + wxString::FromUTF8( err->message );
368
369 wxLogError( msg );
370 return false;
371 }
372
373 if( !InitPgm( false ) )
374 {
375 // Clean up
376 OnPgmExit();
377 return false;
378 }
379
380#if !defined(BUILD_KIWAY_DLL)
381
382 // Only bitmap2component and pcb_calculator use this code currently, as they
383 // are not split to use single_top as a link image separate from a *.kiface.
384 // i.e. they are single part link images so don't need to load a *.kiface.
385
386 // Get the getter, it is statically linked into this binary image.
387 KIFACE_GETTER_FUNC* ki_getter = &KIFACE_GETTER;
388
389 int kiface_version;
390
391 // Get the KIFACE.
392 KIFACE* kiface = ki_getter( &kiface_version, KIFACE_VERSION, this );
393
394 // Trick the KIWAY into thinking it loaded a KIFACE, by recording the KIFACE
395 // in the KIWAY. It needs to be there for KIWAY::OnKiwayEnd() anyways.
396 Kiway.set_kiface( KIWAY::KifaceType( TOP_FRAME ), kiface );
397#endif
398
399 // Tell the settings manager about the current Kiway
400 GetSettingsManager().SetKiway( &Kiway );
401
402 GetSettingsManager().RegisterSettings( new KICAD_SETTINGS );
403
404
405 if( const COMMON_SETTINGS* cfg = Pgm().GetCommonSettings() )
406 {
407 if( cfg->m_Appearance.app_theme == APP_THEME::DARK )
409 else if( cfg->m_Appearance.app_theme == APP_THEME::AUTO )
411 }
412
413#ifdef KICAD_IPC_API
414 // Create the API server thread once the app event loop exists
415 m_api_server = std::make_unique<KICAD_API_SERVER>();
416#endif
417
418 // Use KIWAY to create a top window, which registers its existence also.
419 // "TOP_FRAME" is a macro that is passed on compiler command line from CMake,
420 // and is one of the types in FRAME_T.
421 KIWAY_PLAYER* frame = Kiway.Player( TOP_FRAME, true );
422
423 if( frame == nullptr )
424 {
425 // Clean up
426 OnPgmExit();
427 return false;
428 }
429
430 Kiway.SetTop( frame );
431
432 STARTWIZARD startWizard;
433 startWizard.CheckAndRun( frame );
434
435 // Load library tables after startup wizard
436 GetLibraryManager().LoadGlobalTables();
437
438 App().SetTopWindow( frame ); // wxApp gets a face.
439 App().SetAppDisplayName( frame->GetAboutTitle() );
440
441 wxString relaunchDisplayName = frame->GetAboutTitle() + " " + GetMajorMinorVersion();
443
444 // Allocate a slice of time to show the frame and update wxWidgets widgets
445 // (especially setting valid sizes) after creating frame and before calling
446 // OpenProjectFiles() that can update/use some widgets.
447 // The 2 calls to wxSafeYield are needed on wxGTK for best results.
448 wxSafeYield();
449 HideSplash();
450 frame->Show();
451 wxSafeYield();
452
453 // Now after the frame processing, the rest of the positional args are files
454 std::vector<wxString> fileArgs;
455
456
457 static const wxCmdLineEntryDesc desc[] = {
458 { wxCMD_LINE_PARAM, nullptr, nullptr, "File to load", wxCMD_LINE_VAL_STRING,
459 wxCMD_LINE_PARAM_MULTIPLE | wxCMD_LINE_PARAM_OPTIONAL },
460 { wxCMD_LINE_NONE, nullptr, nullptr, nullptr, wxCMD_LINE_VAL_NONE, 0 }
461 };
462
463 wxCmdLineParser parser( App().argc, App().argv );
464 parser.SetDesc( desc );
465 parser.Parse( false );
466
467 if( parser.GetParamCount() )
468 {
469 /*
470 gerbview handles multiple project data files, i.e. gerber files on
471 cmd line. Others currently do not, they handle only one. For common
472 code simplicity we simply pass all the arguments in however, each
473 program module can do with them what they want, ignore, complain
474 whatever. We don't establish policy here, as this is a multi-purpose
475 launcher.
476 */
477
478 for( size_t i = 0; i < parser.GetParamCount(); i++ )
479 fileArgs.push_back( parser.GetParam( i ) );
480
481 // special attention to a single argument: argv[1] (==argSet[0])
482 if( fileArgs.size() == 1 )
483 {
484 wxFileName argv1( fileArgs[0] );
485
486#if defined(PGM_DATA_FILE_EXT)
487 // PGM_DATA_FILE_EXT, if present, may be different for each compile,
488 // it may come from CMake on the compiler command line, but often does not.
489 // This facility is mostly useful for those program footprints
490 // supporting a single argv[1].
491 if( !argv1.GetExt() )
492 argv1.SetExt( wxT( PGM_DATA_FILE_EXT ) );
493#endif
494 argv1.MakeAbsolute();
495
496 fileArgs[0] = argv1.GetFullPath();
497 }
498
499 frame->OpenProjectFiles( fileArgs );
500 }
501
502 if( KIFACE* topFrame = Kiway.KiFACE( KIWAY::KifaceType( TOP_FRAME ) ) )
503 topFrame->PreloadLibraries( &Kiway );
504
506
507#ifdef KICAD_IPC_API
508 m_api_server->SetReadyToReply();
509#endif
510
511 return true;
512}
wxString GetMajorMinorVersion()
Get only the major and minor version in a string major.minor.
wxString GetAboutTitle() const
virtual void Init()=0
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:315
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:343
wxWindow * GetBlockingDialog()
Gets the window pointer to the blocking dialog (to send it signals)
Definition kiway.cpp:690
static const wxString & GetExecutablePath()
Definition paths.cpp:671
virtual COMMON_SETTINGS * GetCommonSettings() const
Definition pgm_base.cpp:541
virtual wxApp & App()
Return a bare naked wxApp which may come from wxPython, SINGLE_TOP, or kicad.exe.
Definition pgm_base.cpp:211
void PreloadDesignBlockLibraries(KIWAY *aKiway)
Starts a background job to preload the global and project design block libraries.
Definition pgm_base.cpp:887
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:411
void Destroy()
Definition pgm_base.cpp:190
void HandleException(std::exception_ptr aPtr, bool aUnhandled=false)
A exception handler to be used at the top level if exceptions bubble up that for.
Definition pgm_base.cpp:802
std::vector< void * > m_ModalDialogs
Definition pgm_base.h:392
bool InitPgm(bool aHeadless=false, bool aIsUnitTest=false)
Initialize this program.
Definition pgm_base.cpp:327
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:839
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition pgm_base.h:130
void HideSplash()
Definition pgm_base.cpp:316
virtual LIBRARY_MANAGER & GetLibraryManager() const
Definition pgm_base.h:132
void SaveCommonSettings()
Save the program (process) settings subset which are stored .kicad_common.
Definition pgm_base.cpp:532
void CheckAndRun(wxWindow *parent)
This file is part of the common library.
void SetGitBackend(GIT_BACKEND *aBackend)
GIT_BACKEND * GetGitBackend()
KIFACE * KIFACE_GETTER_FUNC(int *aKIFACEversion, int aKIWAYversion, PGM_BASE *aProgram)
Point to the one and only KIFACE export.
Definition kiway.h:553
#define KIFACE_GETTER
Definition kiway.h:113
#define KIFACE_VERSION
Definition kiway.h:112
#define KFCTL_STANDALONE
Running as a standalone Top.
Definition kiway.h:163
This file contains miscellaneous commonly used macros and functions.
bool Init()
Perform application-specific initialization tasks.
Definition unix/app.cpp:40
void EnableDarkMode(bool aForce)
Definition unix/app.cpp:58
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.
void SetPgm(PGM_BASE *pgm)
PGM_BASE & Pgm()
The global program "get" accessor.
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
void OnUnhandledException() override
bool OnInit() override
int FilterEvent(wxEvent &aEvent) override
Implement a participant in the KIWAY alchemy.
Definition kiway.h:156
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.