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>
63
64#ifdef KICAD_USE_SENTRY
65#include <sentry.h>
66#endif
67
68#ifdef KICAD_IPC_API
69#include <api/api_server.h>
70#endif
71
72// Only a single KIWAY is supported in this single_top top level component,
73// which is dedicated to loading only a single DSO.
75
76
77// implement a PGM_BASE and a wxApp side by side:
78
82static struct PGM_SINGLE_TOP : public PGM_BASE
83{
84 bool OnPgmInit();
85
86 void OnPgmExit()
87 {
88
89 Kiway.OnKiwayEnd();
90
91#ifdef KICAD_IPC_API
92 m_api_server.reset();
93#endif
94
96 {
98 m_settings_manager->Save();
99 }
100
101 // Destroy everything in PGM_BASE, especially wxSingleInstanceCheckerImpl
102 // earlier than wxApp and earlier than static destruction would.
104 git_libgit2_shutdown();
105 }
106
107 void MacOpenFile( const wxString& aFileName ) override
108 {
109 wxFileName filename( aFileName );
110
111 if( filename.FileExists() )
112 {
113 #if 0
114 // this pulls in EDA_DRAW_FRAME type info, which we don't want in
115 // the single_top link image.
116 KIWAY_PLAYER* frame = dynamic_cast<KIWAY_PLAYER*>( App().GetTopWindow() );
117 #else
118 KIWAY_PLAYER* frame = (KIWAY_PLAYER*) App().GetTopWindow();
119 #endif
120 if( frame )
121 {
122 if( wxWindow* blocking_win = frame->Kiway().GetBlockingDialog() )
123 blocking_win->Close( true );
124
125 frame->OpenProjectFiles( std::vector<wxString>( 1, aFileName ) );
126 }
127 }
128 }
129
131
132
133// A module to allow Html module initialization/cleanup
134// When a wxHtmlWindow is used *only* in a dll/so module, the Html text is displayed
135// as plain text.
136// This helper class is just used to force wxHtmlWinParser initialization
137// see https://groups.google.com/forum/#!topic/wx-users/FF0zv5qGAT0
138class HtmlModule: public wxModule
139{
140public:
142 virtual bool OnInit() override { AddDependency( CLASSINFO( wxHtmlWinParser ) ); return true; };
143 virtual void OnExit() override {};
144
145private:
147};
148
150
151
152#ifdef NDEBUG
153// Define a custom assertion handler
154void CustomAssertHandler( const wxString& file,
155 int line,
156 const wxString& func,
157 const wxString& cond,
158 const wxString& msg )
159{
160 Pgm().HandleAssert( file, line, func, cond, msg );
161}
162#endif
163
164
169struct APP_SINGLE_TOP : public wxApp
170{
171 APP_SINGLE_TOP() : wxApp()
172 {
173 SetPgm( &program );
174
175 // Init the environment each platform wants
177 }
178
179
180 bool OnInit() override
181 {
182#ifdef NDEBUG
183 // These checks generate extra assert noise
184 wxSizerFlags::DisableConsistencyChecks();
185 wxDISABLE_DEBUG_SUPPORT();
186 wxSetAssertHandler( CustomAssertHandler );
187#endif
188
189 // Perform platform-specific init tasks
190 if( !KIPLATFORM::APP::Init() )
191 return false;
192
193#ifndef DEBUG
194 // Enable logging traces to the console in release build.
195 // This is usually disabled, but it can be useful for users to run to help
196 // debug issues and other problems.
197 if( wxGetEnv( wxS( "KICAD_ENABLE_WXTRACE" ), nullptr ) )
198 {
199 wxLog::EnableLogging( true );
200 wxLog::SetLogLevel( wxLOG_Trace );
201 }
202#endif
203
204 // Force wxHtmlWinParser initialization when a wxHtmlWindow is used only
205 // in a shared library (.so or .dll file)
206 // Otherwise the Html text is displayed as plain text.
207 HtmlModule html_init;
208
209 try
210 {
211 return program.OnPgmInit();
212 }
213 catch( ... )
214 {
215 Pgm().HandleException( std::current_exception() );
216 }
217
218 program.OnPgmExit();
219
220 return false;
221 }
222
223 int OnExit() override
224 {
225 program.OnPgmExit();
226 return wxApp::OnExit();
227 }
228
229 int OnRun() override
230 {
231 int ret = -1;
232
233 try
234 {
235 ret = wxApp::OnRun();
236 }
237 catch(...)
238 {
239 Pgm().HandleException( std::current_exception() );
240 }
241
242 return ret;
243 }
244
245 int FilterEvent( wxEvent& aEvent ) override
246 {
247 if( aEvent.GetEventType() == wxEVT_SHOW )
248 {
249 wxShowEvent& event = static_cast<wxShowEvent&>( aEvent );
250 wxDialog* dialog = dynamic_cast<wxDialog*>( event.GetEventObject() );
251
252 std::vector<void*>& dlgs = Pgm().m_ModalDialogs;
253
254 if( dialog )
255 {
256 if( event.IsShown() && dialog->IsModal() )
257 {
258 dlgs.push_back( dialog );
259 }
260 // Under GTK, sometimes the modal flag is cleared before hiding
261 else if( !event.IsShown() && !dlgs.empty() )
262 {
263 // If we close the expected dialog, remove it from our stack
264 if( dlgs.back() == dialog )
265 dlgs.pop_back();
266 // If an out-of-order, remove all dialogs added after the closed one
267 else if( auto it = std::find( dlgs.begin(), dlgs.end(), dialog ); it != dlgs.end() )
268 dlgs.erase( it, dlgs.end() );
269 }
270 }
271 }
272
273 return Event_Skip;
274 }
275
276#if defined( DEBUG )
284 virtual bool OnExceptionInMainLoop() override
285 {
286 try
287 {
288 throw;
289 }
290 catch( ... )
291 {
292 Pgm().HandleException( std::current_exception() );
293 }
294
295 return false; // continue on. Return false to abort program
296 }
297#endif
298
299#ifdef __WXMAC__
300
308 void MacOpenFile( const wxString& aFileName ) override
309 {
310 Pgm().MacOpenFile( aFileName );
311 }
312
313#endif
314};
315
316IMPLEMENT_APP( APP_SINGLE_TOP )
317
318
320{
321#if defined(DEBUG)
322 wxString absoluteArgv0 = wxStandardPaths::Get().GetExecutablePath();
323
324 if( !wxIsAbsolutePath( absoluteArgv0 ) )
325 {
326 wxLogError( wxT( "No meaningful argv[0]" ) );
327 return false;
328 }
329#endif
330
331 // Initialize the git library before trying to initialize individual programs
332 int gitInit = git_libgit2_init();
333
334 if( gitInit < 0 )
335 {
336 const git_error* err = git_error_last();
337 wxString msg = wxS( "Failed to initialize git library" );
338
339 if( err && err->message )
340 msg += wxS( ": " ) + wxString::FromUTF8( err->message );
341
342 wxLogError( msg );
343 return false;
344 }
345
346 // Not all KiCad applications use the python stuff. skip python init
347 // for these apps.
348 bool skip_python_initialization = false;
349
350#if defined( BITMAP_2_CMP ) || defined( PL_EDITOR ) || defined( GERBVIEW ) || \
351 defined( PCB_CALCULATOR_BUILD )
352 skip_python_initialization = true;
353#endif
354
355 if( !InitPgm( false, skip_python_initialization ) )
356 {
357 // Clean up
358 OnPgmExit();
359 return false;
360 }
361
362#if !defined(BUILD_KIWAY_DLL)
363
364 // Only bitmap2component and pcb_calculator use this code currently, as they
365 // are not split to use single_top as a link image separate from a *.kiface.
366 // i.e. they are single part link images so don't need to load a *.kiface.
367
368 // Get the getter, it is statically linked into this binary image.
369 KIFACE_GETTER_FUNC* ki_getter = &KIFACE_GETTER;
370
371 int kiface_version;
372
373 // Get the KIFACE.
374 KIFACE* kiface = ki_getter( &kiface_version, KIFACE_VERSION, this );
375
376 // Trick the KIWAY into thinking it loaded a KIFACE, by recording the KIFACE
377 // in the KIWAY. It needs to be there for KIWAY::OnKiwayEnd() anyways.
378 Kiway.set_kiface( KIWAY::KifaceType( TOP_FRAME ), kiface );
379#endif
380
381 // Tell the settings manager about the current Kiway
383
385
386#ifdef KICAD_IPC_API
387 // Create the API server thread once the app event loop exists
388 m_api_server = std::make_unique<KICAD_API_SERVER>();
389#endif
390
391 // Use KIWAY to create a top window, which registers its existence also.
392 // "TOP_FRAME" is a macro that is passed on compiler command line from CMake,
393 // and is one of the types in FRAME_T.
394 KIWAY_PLAYER* frame = Kiway.Player( TOP_FRAME, true );
395
396 if( frame == nullptr )
397 {
398 // Clean up
399 OnPgmExit();
400 return false;
401 }
402
403 Kiway.SetTop( frame );
404
405 STARTWIZARD startWizard;
406 startWizard.CheckAndRun( frame );
407
408 // Load library tables after startup wizard
409 GetLibraryManager().LoadGlobalTables();
410
411 // Preload libraries, since for single-top this won't have been done earlier
412 if( KIFACE* topFrame = Kiway.KiFACE( KIWAY::KifaceType( TOP_FRAME ) ) )
413 topFrame->PreloadLibraries( &Kiway );
414
416
417 App().SetTopWindow( frame ); // wxApp gets a face.
418 App().SetAppDisplayName( frame->GetAboutTitle() );
419
420 wxString relaunchDisplayName = frame->GetAboutTitle() + " " + GetMajorMinorVersion();
422
423 // Allocate a slice of time to show the frame and update wxWidgets widgets
424 // (especially setting valid sizes) after creating frame and before calling
425 // OpenProjectFiles() that can update/use some widgets.
426 // The 2 calls to wxSafeYield are needed on wxGTK for best results.
427 wxSafeYield();
428 HideSplash();
429 frame->Show();
430 wxSafeYield();
431
432 // Now after the frame processing, the rest of the positional args are files
433 std::vector<wxString> fileArgs;
434
435
436 static const wxCmdLineEntryDesc desc[] = {
437 { wxCMD_LINE_PARAM, nullptr, nullptr, "File to load", wxCMD_LINE_VAL_STRING,
438 wxCMD_LINE_PARAM_MULTIPLE | wxCMD_LINE_PARAM_OPTIONAL },
439 { wxCMD_LINE_NONE, nullptr, nullptr, nullptr, wxCMD_LINE_VAL_NONE, 0 }
440 };
441
442 wxCmdLineParser parser( App().argc, App().argv );
443 parser.SetDesc( desc );
444 parser.Parse( false );
445
446 if( parser.GetParamCount() )
447 {
448 /*
449 gerbview handles multiple project data files, i.e. gerber files on
450 cmd line. Others currently do not, they handle only one. For common
451 code simplicity we simply pass all the arguments in however, each
452 program module can do with them what they want, ignore, complain
453 whatever. We don't establish policy here, as this is a multi-purpose
454 launcher.
455 */
456
457 for( size_t i = 0; i < parser.GetParamCount(); i++ )
458 fileArgs.push_back( parser.GetParam( i ) );
459
460 // special attention to a single argument: argv[1] (==argSet[0])
461 if( fileArgs.size() == 1 )
462 {
463 wxFileName argv1( fileArgs[0] );
464
465#if defined(PGM_DATA_FILE_EXT)
466 // PGM_DATA_FILE_EXT, if present, may be different for each compile,
467 // it may come from CMake on the compiler command line, but often does not.
468 // This facility is mostly useful for those program footprints
469 // supporting a single argv[1].
470 if( !argv1.GetExt() )
471 argv1.SetExt( wxT( PGM_DATA_FILE_EXT ) );
472#endif
473 argv1.MakeAbsolute();
474
475 fileArgs[0] = argv1.GetFullPath();
476 }
477
478 frame->OpenProjectFiles( fileArgs );
479 }
480
481#ifdef KICAD_IPC_API
482 m_api_server->SetReadyToReply();
483#endif
484
485 return true;
486}
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:678
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:386
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:367
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:130
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)