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