KiCad PCB EDA Suite
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>
50
51#include <kiplatform/app.h>
53
54
55// Only a single KIWAY is supported in this single_top top level component,
56// which is dedicated to loading only a single DSO.
58
59
60// implement a PGM_BASE and a wxApp side by side:
61
66static struct PGM_SINGLE_TOP : public PGM_BASE
67{
68 bool OnPgmInit();
69
70 void OnPgmExit()
71 {
73
75 {
77 m_settings_manager->Save();
78 }
79
80 // Destroy everything in PGM_BASE, especially wxSingleInstanceCheckerImpl
81 // earlier than wxApp and earlier than static destruction would.
83 }
84
85 void MacOpenFile( const wxString& aFileName ) override
86 {
87 wxFileName filename( aFileName );
88
89 if( filename.FileExists() )
90 {
91 #if 0
92 // this pulls in EDA_DRAW_FRAME type info, which we don't want in
93 // the single_top link image.
94 KIWAY_PLAYER* frame = dynamic_cast<KIWAY_PLAYER*>( App().GetTopWindow() );
95 #else
96 KIWAY_PLAYER* frame = (KIWAY_PLAYER*) App().GetTopWindow();
97 #endif
98 if( frame )
99 {
100 if( wxWindow* blocking_win = frame->Kiway().GetBlockingDialog() )
101 blocking_win->Close( true );
102
103 frame->OpenProjectFiles( std::vector<wxString>( 1, aFileName ) );
104 }
105 }
106 }
107
109
110
112{
113 return program;
114}
115
116// A module to allow Html module initialization/cleanup
117// When a wxHtmlWindow is used *only* in a dll/so module, the Html text is displayed
118// as plain text.
119// This helper class is just used to force wxHtmlWinParser initialization
120// see https://groups.google.com/forum/#!topic/wx-users/FF0zv5qGAT0
121class HtmlModule: public wxModule
122{
123public:
125 virtual bool OnInit() override { AddDependency( CLASSINFO( wxHtmlWinParser ) ); return true; };
126 virtual void OnExit() override {};
127private:
129};
131
137struct APP_SINGLE_TOP : public wxApp
138{
139 APP_SINGLE_TOP() : wxApp()
140 {
141 // Init the environment each platform wants
143 }
144
145
146 bool OnInit() override
147 {
148 // Perform platform-specific init tasks
149 if( !KIPLATFORM::APP::Init() )
150 return false;
151
152 // Force wxHtmlWinParser initialization when a wxHtmlWindow is used only
153 // in a shared library (.so or .dll file)
154 // Otherwise the Html text is displayed as plain text.
155 HtmlModule html_init;
156
157 try
158 {
159 return program.OnPgmInit();
160 }
161 catch( const std::exception& e )
162 {
163 wxLogError( wxT( "Unhandled exception class: %s what: %s" ),
164 FROM_UTF8( typeid( e ).name() ), FROM_UTF8( e.what() ) );
165 }
166 catch( const IO_ERROR& ioe )
167 {
168 wxLogError( ioe.What() );
169 }
170 catch(...)
171 {
172 wxLogError( wxT( "Unhandled exception of unknown type" ) );
173 }
174
176
177 return false;
178 }
179
180 int OnExit() override
181 {
183 return wxApp::OnExit();
184 }
185
186 int OnRun() override
187 {
188 int ret = -1;
189
190 try
191 {
192 ret = wxApp::OnRun();
193 }
194 catch( const std::exception& e )
195 {
196 wxLogError( wxT( "Unhandled exception class: %s what: %s" ),
197 FROM_UTF8( typeid( e ).name() ), FROM_UTF8( e.what() ) );
198 }
199 catch( const IO_ERROR& ioe )
200 {
201 wxLogError( ioe.What() );
202 }
203 catch(...)
204 {
205 wxLogError( wxT( "Unhandled exception of unknown type" ) );
206 }
207
208 return ret;
209 }
210
211 int FilterEvent( wxEvent& aEvent ) override
212 {
213 if( aEvent.GetEventType() == wxEVT_SHOW )
214 {
215 wxShowEvent& event = static_cast<wxShowEvent&>( aEvent );
216 wxDialog* dialog = dynamic_cast<wxDialog*>( event.GetEventObject() );
217
218 if( dialog && dialog->IsModal() )
219 Pgm().m_ModalDialogCount += event.IsShown() ? 1 : -1;
220 }
221
222 return Event_Skip;
223 }
224
225#if defined( DEBUG )
233 virtual bool OnExceptionInMainLoop() override
234 {
235 try
236 {
237 throw;
238 }
239 catch( const std::exception& e )
240 {
241 wxLogError( "Unhandled exception class: %s what: %s",
242 FROM_UTF8( typeid(e).name() ),
243 FROM_UTF8( e.what() ) );
244 }
245 catch( const IO_ERROR& ioe )
246 {
247 wxLogError( ioe.What() );
248 }
249 catch(...)
250 {
251 wxLogError( "Unhandled exception of unknown type" );
252 }
253
254 return false; // continue on. Return false to abort program
255 }
256#endif
257
258#ifdef __WXMAC__
259
266 void MacOpenFile( const wxString& aFileName ) override
267 {
268 Pgm().MacOpenFile( aFileName );
269 }
270
271#endif
272};
273
274IMPLEMENT_APP( APP_SINGLE_TOP )
275
276
277bool PGM_SINGLE_TOP::OnPgmInit()
278{
279#if defined(DEBUG)
280 wxString absoluteArgv0 = wxStandardPaths::Get().GetExecutablePath();
281
282 if( !wxIsAbsolutePath( absoluteArgv0 ) )
283 {
284 wxLogError( wxT( "No meaningful argv[0]" ) );
285 return false;
286 }
287#endif
288
289 // Not all kicad applications use the python stuff. skip python init
290 // for these apps.
291 bool skip_python_initialization = false;
292#if defined( BITMAP_2_CMP ) || defined( PL_EDITOR ) || defined( GERBVIEW ) ||\
293 defined( PCB_CALCULATOR_BUILD )
294 skip_python_initialization = true;
295#endif
296
297 if( !InitPgm( false, skip_python_initialization ) )
298 {
299 // Clean up
300 OnPgmExit();
301 return false;
302 }
303
304#if !defined(BUILD_KIWAY_DLL)
305
306 // Only bitmap2component and pcb_calculator use this code currently, as they
307 // are not split to use single_top as a link image separate from a *.kiface.
308 // i.e. they are single part link images so don't need to load a *.kiface.
309
310 // Get the getter, it is statically linked into this binary image.
311 KIFACE_GETTER_FUNC* ki_getter = &KIFACE_GETTER;
312
313 int kiface_version;
314
315 // Get the KIFACE.
316 KIFACE* kiface = ki_getter( &kiface_version, KIFACE_VERSION, this );
317
318 // Trick the KIWAY into thinking it loaded a KIFACE, by recording the KIFACE
319 // in the KIWAY. It needs to be there for KIWAY::OnKiwayEnd() anyways.
320 Kiway.set_kiface( KIWAY::KifaceType( TOP_FRAME ), kiface );
321#endif
322
323 static const wxCmdLineEntryDesc desc[] = {
324 { wxCMD_LINE_OPTION, "f", "frame", "Frame to load", wxCMD_LINE_VAL_STRING, 0 },
325 { wxCMD_LINE_PARAM, nullptr, nullptr, "File to load", wxCMD_LINE_VAL_STRING,
326 wxCMD_LINE_PARAM_MULTIPLE | wxCMD_LINE_PARAM_OPTIONAL },
327 { wxCMD_LINE_NONE, nullptr, nullptr, nullptr, wxCMD_LINE_VAL_NONE, 0 }
328 };
329
330 wxCmdLineParser parser( App().argc, App().argv );
331 parser.SetDesc( desc );
332 parser.Parse( false );
333
334 FRAME_T appType = TOP_FRAME;
335
336 const struct
337 {
338 wxString name;
339 FRAME_T type;
340 } frameTypes[] = {
341 { wxT( "pcb" ), FRAME_PCB_EDITOR },
342 { wxT( "fpedit" ), FRAME_FOOTPRINT_EDITOR },
343 { wxT( "" ), FRAME_T_COUNT }
344 };
345
346 wxString frameName;
347
348 if( parser.Found( "frame", &frameName ) )
349 {
350 appType = FRAME_T_COUNT;
351
352 for( const auto& it : frameTypes )
353 {
354 if( it.name == frameName )
355 appType = it.type;
356 }
357
358 if( appType == FRAME_T_COUNT )
359 {
360 wxLogError( wxT( "Unknown frame: %s" ), frameName );
361 // Clean up
362 OnPgmExit();
363 return false;
364 }
365 }
366
367 // Tell the settings manager about the current Kiway
369
370 // Use KIWAY to create a top window, which registers its existence also.
371 // "TOP_FRAME" is a macro that is passed on compiler command line from CMake,
372 // and is one of the types in FRAME_T.
373 KIWAY_PLAYER* frame = Kiway.Player( appType, true );
374
375 if( frame == nullptr )
376 {
377 return false;
378 }
379
380 Kiway.SetTop( frame );
381
382 App().SetTopWindow( frame ); // wxApp gets a face.
383 App().SetAppDisplayName( frame->GetAboutTitle() );
384
385 // Allocate a slice of time to show the frame and update wxWidgets widgets
386 // (especially setting valid sizes) after creating frame and before calling
387 // OpenProjectFiles() that can update/use some widgets.
388 // The 2 calls to wxSafeYield are needed on wxGTK for best results.
389 wxSafeYield();
390 frame->Show();
391 wxSafeYield();
392
393 // Individual frames may provide additional option/switch processing, but for compatibility,
394 // any positional arguments are treated as a list of files to pass to OpenProjectFiles
395 frame->ParseArgs( parser );
396
397 // Now after the frame processing, the rest of the positional args are files
398 std::vector<wxString> fileArgs;
399
400 if( parser.GetParamCount() )
401 {
402 /*
403 gerbview handles multiple project data files, i.e. gerber files on
404 cmd line. Others currently do not, they handle only one. For common
405 code simplicity we simply pass all the arguments in however, each
406 program module can do with them what they want, ignore, complain
407 whatever. We don't establish policy here, as this is a multi-purpose
408 launcher.
409 */
410
411 for( size_t i = 0; i < parser.GetParamCount(); i++ )
412 fileArgs.push_back( parser.GetParam( i ) );
413
414 // special attention to a single argument: argv[1] (==argSet[0])
415 if( fileArgs.size() == 1 )
416 {
417 wxFileName argv1( fileArgs[0] );
418
419#if defined(PGM_DATA_FILE_EXT)
420 // PGM_DATA_FILE_EXT, if present, may be different for each compile,
421 // it may come from CMake on the compiler command line, but often does not.
422 // This facility is mostly useful for those program footprints
423 // supporting a single argv[1].
424 if( !argv1.GetExt() )
425 argv1.SetExt( wxT( PGM_DATA_FILE_EXT ) );
426#endif
427 argv1.MakeAbsolute();
428
429 fileArgs[0] = argv1.GetFullPath();
430 }
431
432 // Use the KIWAY_PLAYER::OpenProjectFiles() API function:
433 if( !frame->OpenProjectFiles( fileArgs ) )
434 {
435 // OpenProjectFiles() API asks that it report failure to the UI.
436 // Nothing further to say here.
437
438 // We've already initialized things at this point, but wx won't call OnExit if
439 // we fail out. Call our own cleanup routine here to ensure the relevant resources
440 // are freed at the right time (if they aren't, segfaults will occur).
441 OnPgmExit();
442
443 // Fail the process startup if the file could not be opened,
444 // although this is an optional choice, one that can be reversed
445 // also in the KIFACE specific OpenProjectFiles() return value.
446 return false;
447 }
448 }
449
450 return true;
451}
const char * name
Definition: DXF_plotter.cpp:56
const wxString & GetAboutTitle() const
virtual bool OnInit() override
Definition: single_top.cpp:125
virtual void OnExit() override
Definition: single_top.cpp:126
wxDECLARE_DYNAMIC_CLASS(HtmlModule)
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Definition: ki_exception.h:76
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:30
KIWAY & Kiway() const
Return a reference to the KIWAY that this object has an opportunity to participate in.
Definition: kiway_holder.h:53
A wxFrame capable of the OpenProjectFiles function, meaning it can load a portion of a KiCad project.
Definition: kiway_player.h:66
virtual void ParseArgs(wxCmdLineParser &aParser)
Handle command-line arguments in a frame-specific way.
Definition: kiway_player.h:139
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:118
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
Definition: kiway.h:267
virtual KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=nullptr)
Return the KIWAY_PLAYER* given a FRAME_T.
Definition: kiway.cpp:394
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:332
bool set_kiface(FACE_T aFaceType, KIFACE *aKiface)
Definition: kiway.h:422
wxWindow * GetBlockingDialog()
Gets the window pointer to the blocking dialog (to send it signals)
Definition: kiway.cpp:617
void OnKiwayEnd()
Definition: kiway.cpp:672
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:84
Container for data for KiCad programs.
Definition: pgm_base.h:94
virtual wxApp & App()
Returns a bare naked wxApp which may come from wxPython, SINGLE_TOP, or kicad.exe.
Definition: pgm_base.cpp:152
std::unique_ptr< SETTINGS_MANAGER > m_settings_manager
Definition: pgm_base.h:325
void Destroy()
Definition: pgm_base.cpp:140
virtual const wxString & GetExecutablePath() const
Definition: pgm_base.h:160
void SaveCommonSettings()
Save the program (process) settings subset which are stored .kicad_common.
Definition: pgm_base.cpp:564
void SetKiway(KIWAY *aKiway)
Associate this setting manager with the given Kiway.
This file is part of the common library.
return & kiface
Definition: cvpcb.cpp:112
FRAME_T
The set of EDA_BASE_FRAME derivatives, typically stored in EDA_BASE_FRAME::m_Ident.
Definition: frame_type.h:33
@ FRAME_PCB_EDITOR
Definition: frame_type.h:40
@ FRAME_T_COUNT
Definition: frame_type.h:66
@ FRAME_FOOTPRINT_EDITOR
Definition: frame_type.h:41
KIWAY Kiway
KIFACE * KIFACE_GETTER_FUNC(int *aKIFACEversion, int aKIWAYversion, PGM_BASE *aProgram)
Point to the one and only KIFACE export.
Definition: kiway.h:478
#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:157
This file contains miscellaneous commonly used macros and functions.
static wxString FROM_UTF8(const char *cstring)
Convert a UTF8 encoded C string to a wxString for all wxWidgets build modes.
Definition: macros.h:110
bool Init()
Perform application-specific initialization tasks.
Definition: gtk/app.cpp:40
void Init()
Perform environment initialization tasks.
SETTINGS_MANAGER * GetSettingsManager()
see class PGM_BASE
PGM_SINGLE_TOP program
wxIMPLEMENT_DYNAMIC_CLASS(HtmlModule, wxModule)
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:111
Struct APP_SINGLE_TOP implements a bare naked wxApp (so that we don't become dependent on functionali...
Definition: single_top.cpp:138
int OnRun() override
Definition: single_top.cpp:186
int OnExit() override
Definition: single_top.cpp:180
bool OnInit() override
Definition: single_top.cpp:146
int FilterEvent(wxEvent &aEvent) override
Definition: single_top.cpp:211
Implement a participant in the KIWAY alchemy.
Definition: kiway.h:150
Struct PGM_SINGLE_TOP implements PGM_BASE with its own OnPgmInit() and OnPgmExit().
Definition: single_top.cpp:67
void MacOpenFile(const wxString &aFileName) override
Specific to MacOSX (not used under Linux or Windows).
Definition: single_top.cpp:85
void OnPgmExit()
Definition: single_top.cpp:70