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 (C) 2014-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
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/filename.h>
40#include <wx/stdpaths.h>
41#include <wx/snglinst.h>
42#include <wx/html/htmlwin.h>
43
44#include <kiway.h>
45#include <pgm_base.h>
46#include <kiway_player.h>
47#include <macros.h>
48#include <confirm.h>
51
52#include <kiplatform/app.h>
54
55#include <git2.h>
56
57#ifdef KICAD_USE_SENTRY
58#include <sentry.h>
59#endif
60
61#ifdef KICAD_IPC_API
62#include <api/api_server.h>
63#endif
64
65// Only a single KIWAY is supported in this single_top top level component,
66// which is dedicated to loading only a single DSO.
68
69
70// implement a PGM_BASE and a wxApp side by side:
71
76static struct PGM_SINGLE_TOP : public PGM_BASE
77{
78 bool OnPgmInit();
79
80 void OnPgmExit()
81 {
82
84
85#ifdef KICAD_IPC_API
86 m_api_server.reset();
87#endif
88
90 {
92 m_settings_manager->Save();
93 }
94
95 // Destroy everything in PGM_BASE, especially wxSingleInstanceCheckerImpl
96 // earlier than wxApp and earlier than static destruction would.
98 git_libgit2_shutdown();
99 }
100
101 void MacOpenFile( const wxString& aFileName ) override
102 {
103 wxFileName filename( aFileName );
104
105 if( filename.FileExists() )
106 {
107 #if 0
108 // this pulls in EDA_DRAW_FRAME type info, which we don't want in
109 // the single_top link image.
110 KIWAY_PLAYER* frame = dynamic_cast<KIWAY_PLAYER*>( App().GetTopWindow() );
111 #else
112 KIWAY_PLAYER* frame = (KIWAY_PLAYER*) App().GetTopWindow();
113 #endif
114 if( frame )
115 {
116 if( wxWindow* blocking_win = frame->Kiway().GetBlockingDialog() )
117 blocking_win->Close( true );
118
119 frame->OpenProjectFiles( std::vector<wxString>( 1, aFileName ) );
120 }
121 }
122 }
123
125
126// A module to allow Html module initialization/cleanup
127// When a wxHtmlWindow is used *only* in a dll/so module, the Html text is displayed
128// as plain text.
129// This helper class is just used to force wxHtmlWinParser initialization
130// see https://groups.google.com/forum/#!topic/wx-users/FF0zv5qGAT0
131class HtmlModule: public wxModule
132{
133public:
135 virtual bool OnInit() override { AddDependency( CLASSINFO( wxHtmlWinParser ) ); return true; };
136 virtual void OnExit() override {};
137private:
139};
141
142#ifdef NDEBUG
143// Define a custom assertion handler
144void CustomAssertHandler(const wxString& file,
145 int line,
146 const wxString& func,
147 const wxString& cond,
148 const wxString& msg)
149{
150 Pgm().HandleAssert( file, line, func, cond, msg );
151}
152#endif
153
159struct APP_SINGLE_TOP : public wxApp
160{
161 APP_SINGLE_TOP() : wxApp()
162 {
163 SetPgm( &program );
164 // Init the environment each platform wants
166 }
167
168
169 bool OnInit() override
170 {
171#ifdef NDEBUG
172 // These checks generate extra assert noise
173 wxSizerFlags::DisableConsistencyChecks();
174 wxDISABLE_DEBUG_SUPPORT();
175 wxSetAssertHandler( CustomAssertHandler );
176#endif
177
178 // Perform platform-specific init tasks
179 if( !KIPLATFORM::APP::Init() )
180 return false;
181
182#ifndef DEBUG
183 // Enable logging traces to the console in release build.
184 // This is usually disabled, but it can be useful for users to run to help
185 // debug issues and other problems.
186 if( wxGetEnv( wxS( "KICAD_ENABLE_WXTRACE" ), nullptr ) )
187 {
188 wxLog::EnableLogging( true );
189 wxLog::SetLogLevel( wxLOG_Trace );
190 }
191#endif
192
193 // Force wxHtmlWinParser initialization when a wxHtmlWindow is used only
194 // in a shared library (.so or .dll file)
195 // Otherwise the Html text is displayed as plain text.
196 HtmlModule html_init;
197
198 try
199 {
200 return program.OnPgmInit();
201 }
202 catch( ... )
203 {
204 Pgm().HandleException( std::current_exception() );
205 }
206
208
209 return false;
210 }
211
212 int OnExit() override
213 {
215 return wxApp::OnExit();
216 }
217
218 int OnRun() override
219 {
220 int ret = -1;
221
222 try
223 {
224 ret = wxApp::OnRun();
225 }
226 catch(...)
227 {
228 Pgm().HandleException( std::current_exception() );
229 }
230
231 return ret;
232 }
233
234 int FilterEvent( wxEvent& aEvent ) override
235 {
236 if( aEvent.GetEventType() == wxEVT_SHOW )
237 {
238 wxShowEvent& event = static_cast<wxShowEvent&>( aEvent );
239 wxDialog* dialog = dynamic_cast<wxDialog*>( event.GetEventObject() );
240
241 std::vector<void*>& dlgs = Pgm().m_ModalDialogs;
242
243 if( dialog )
244 {
245 if( event.IsShown() && dialog->IsModal() )
246 {
247 dlgs.push_back( dialog );
248 }
249 // Under GTK, sometimes the modal flag is cleared before hiding
250 else if( !event.IsShown() && !dlgs.empty() )
251 {
252 // If we close the expected dialog, remove it from our stack
253 if( dlgs.back() == dialog )
254 dlgs.pop_back();
255 // If an out-of-order, remove all dialogs added after the closed one
256 else if( auto it = std::find( dlgs.begin(), dlgs.end(), dialog ) ; it != dlgs.end() )
257 dlgs.erase( it, dlgs.end() );
258 }
259 }
260 }
261
262 return Event_Skip;
263 }
264
265#if defined( DEBUG )
273 virtual bool OnExceptionInMainLoop() override
274 {
275 try
276 {
277 throw;
278 }
279 catch( ... )
280 {
281 Pgm().HandleException( std::current_exception() );
282 }
283
284 return false; // continue on. Return false to abort program
285 }
286#endif
287
288#ifdef __WXMAC__
289
296 void MacOpenFile( const wxString& aFileName ) override
297 {
298 Pgm().MacOpenFile( aFileName );
299 }
300
301#endif
302};
303
304IMPLEMENT_APP( APP_SINGLE_TOP )
305
306
307bool PGM_SINGLE_TOP::OnPgmInit()
308{
309#if defined(DEBUG)
310 wxString absoluteArgv0 = wxStandardPaths::Get().GetExecutablePath();
311
312 if( !wxIsAbsolutePath( absoluteArgv0 ) )
313 {
314 wxLogError( wxT( "No meaningful argv[0]" ) );
315 return false;
316 }
317#endif
318
319 // Initialize the git library before trying to initialize individual programs
320 git_libgit2_init();
321
322 // Not all kicad applications use the python stuff. skip python init
323 // for these apps.
324 bool skip_python_initialization = false;
325#if defined( BITMAP_2_CMP ) || defined( PL_EDITOR ) || defined( GERBVIEW ) ||\
326 defined( PCB_CALCULATOR_BUILD )
327 skip_python_initialization = true;
328#endif
329
330 if( !InitPgm( false, skip_python_initialization ) )
331 {
332 // Clean up
333 OnPgmExit();
334 return false;
335 }
336
337#if !defined(BUILD_KIWAY_DLL)
338
339 // Only bitmap2component and pcb_calculator use this code currently, as they
340 // are not split to use single_top as a link image separate from a *.kiface.
341 // i.e. they are single part link images so don't need to load a *.kiface.
342
343 // Get the getter, it is statically linked into this binary image.
344 KIFACE_GETTER_FUNC* ki_getter = &KIFACE_GETTER;
345
346 int kiface_version;
347
348 // Get the KIFACE.
349 KIFACE* kiface = ki_getter( &kiface_version, KIFACE_VERSION, this );
350
351 // Trick the KIWAY into thinking it loaded a KIFACE, by recording the KIFACE
352 // in the KIWAY. It needs to be there for KIWAY::OnKiwayEnd() anyways.
353 Kiway.set_kiface( KIWAY::KifaceType( TOP_FRAME ), kiface );
354#endif
355
356 // Tell the settings manager about the current Kiway
358
360
361#ifdef KICAD_IPC_API
362 // Create the API server thread once the app event loop exists
363 m_api_server = std::make_unique<KICAD_API_SERVER>();
364#endif
365
366 // Use KIWAY to create a top window, which registers its existence also.
367 // "TOP_FRAME" is a macro that is passed on compiler command line from CMake,
368 // and is one of the types in FRAME_T.
369 KIWAY_PLAYER* frame = Kiway.Player( TOP_FRAME, true );
370
371 if( frame == nullptr )
372 {
373 // Clean up
374 OnPgmExit();
375 return false;
376 }
377
378 Kiway.SetTop( frame );
379
380 App().SetTopWindow( frame ); // wxApp gets a face.
381 App().SetAppDisplayName( frame->GetAboutTitle() );
382
383 // Allocate a slice of time to show the frame and update wxWidgets widgets
384 // (especially setting valid sizes) after creating frame and before calling
385 // OpenProjectFiles() that can update/use some widgets.
386 // The 2 calls to wxSafeYield are needed on wxGTK for best results.
387 wxSafeYield();
388 HideSplash();
389 frame->Show();
390 wxSafeYield();
391
392 // Now after the frame processing, the rest of the positional args are files
393 std::vector<wxString> fileArgs;
394
395
396 static const wxCmdLineEntryDesc desc[] = {
397 { wxCMD_LINE_PARAM, nullptr, nullptr, "File to load", wxCMD_LINE_VAL_STRING,
398 wxCMD_LINE_PARAM_MULTIPLE | wxCMD_LINE_PARAM_OPTIONAL },
399 { wxCMD_LINE_NONE, nullptr, nullptr, nullptr, wxCMD_LINE_VAL_NONE, 0 }
400 };
401
402 wxCmdLineParser parser( App().argc, App().argv );
403 parser.SetDesc( desc );
404 parser.Parse( false );
405 if( parser.GetParamCount() )
406 {
407 /*
408 gerbview handles multiple project data files, i.e. gerber files on
409 cmd line. Others currently do not, they handle only one. For common
410 code simplicity we simply pass all the arguments in however, each
411 program module can do with them what they want, ignore, complain
412 whatever. We don't establish policy here, as this is a multi-purpose
413 launcher.
414 */
415
416 for( size_t i = 0; i < parser.GetParamCount(); i++ )
417 fileArgs.push_back( parser.GetParam( i ) );
418
419 // special attention to a single argument: argv[1] (==argSet[0])
420 if( fileArgs.size() == 1 )
421 {
422 wxFileName argv1( fileArgs[0] );
423
424#if defined(PGM_DATA_FILE_EXT)
425 // PGM_DATA_FILE_EXT, if present, may be different for each compile,
426 // it may come from CMake on the compiler command line, but often does not.
427 // This facility is mostly useful for those program footprints
428 // supporting a single argv[1].
429 if( !argv1.GetExt() )
430 argv1.SetExt( wxT( PGM_DATA_FILE_EXT ) );
431#endif
432 argv1.MakeAbsolute();
433
434 fileArgs[0] = argv1.GetFullPath();
435 }
436
437 frame->OpenProjectFiles( fileArgs );
438 }
439
440#ifdef KICAD_IPC_API
441 m_api_server->SetReadyToReply();
442#endif
443
444 return true;
445}
const wxString & GetAboutTitle() const
virtual bool OnInit() override
Definition: single_top.cpp:135
virtual void OnExit() override
Definition: single_top.cpp:136
wxDECLARE_DYNAMIC_CLASS(HtmlModule)
KIWAY & Kiway() const
Return a reference to the KIWAY that this object has an opportunity to participate in.
Definition: kiway_holder.h:55
A wxFrame capable of the OpenProjectFiles function, meaning it can load a portion of a KiCad project.
Definition: kiway_player.h:67
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:115
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:406
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:344
bool set_kiface(FACE_T aFaceType, KIFACE *aKiface)
Definition: kiway.h:442
wxWindow * GetBlockingDialog()
Gets the window pointer to the blocking dialog (to send it signals)
Definition: kiway.cpp:669
void OnKiwayEnd()
Definition: kiway.cpp:732
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
Container for data for KiCad programs.
Definition: pgm_base.h:102
virtual wxApp & App()
Returns a bare naked wxApp which may come from wxPython, SINGLE_TOP, or kicad.exe.
Definition: pgm_base.cpp:181
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:408
void Destroy()
Definition: pgm_base.cpp:165
std::vector< void * > m_ModalDialogs
Definition: pgm_base.h:388
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:938
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:995
virtual const wxString & GetExecutablePath() const
Definition: pgm_base.cpp:1038
void SaveCommonSettings()
Save the program (process) settings subset which are stored .kicad_common.
Definition: pgm_base.cpp:669
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.
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:497
#define KIFACE_GETTER
Definition: kiway.h:111
#define KIFACE_VERSION
The KIWAY and KIFACE classes are used to communicate between various process modules,...
Definition: kiway.h:110
#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.
SETTINGS_MANAGER * GetSettingsManager()
void SetPgm(PGM_BASE *pgm)
Definition: pgm_base.cpp:1071
PGM_BASE & Pgm()
The global Program "get" accessor.
Definition: pgm_base.cpp:1059
see class PGM_BASE
PGM_SINGLE_TOP program
wxIMPLEMENT_DYNAMIC_CLASS(HtmlModule, wxModule)
KIWAY Kiway(KFCTL_STANDALONE)
Struct APP_SINGLE_TOP implements a bare naked wxApp (so that we don't become dependent on functionali...
Definition: single_top.cpp:160
int OnRun() override
Definition: single_top.cpp:218
int OnExit() override
Definition: single_top.cpp:212
bool OnInit() override
Definition: single_top.cpp:169
int FilterEvent(wxEvent &aEvent) override
Definition: single_top.cpp:234
Implement a participant in the KIWAY alchemy.
Definition: kiway.h:151
Struct PGM_SINGLE_TOP implements PGM_BASE with its own OnPgmInit() and OnPgmExit().
Definition: single_top.cpp:77
void MacOpenFile(const wxString &aFileName) override
Specific to MacOSX (not used under Linux or Windows).
Definition: single_top.cpp:101
void OnPgmExit()
Definition: single_top.cpp:80
IFACE KIFACE_BASE kiface("pcb_test_frame", KIWAY::FACE_PCB)