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 <dick@softplc.com>
5  * Copyright (C) 2014 KiCad Developers, see CHANGELOG.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 <macros.h>
39 #include <fctsys.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 <confirm.h>
49 
50 
51 // Only a single KIWAY is supported in this single_top top level component,
52 // which is dedicated to loading only a single DSO.
54 
55 
56 // implement a PGM_BASE and a wxApp side by side:
57 
62 static struct PGM_SINGLE_TOP : public PGM_BASE
63 {
64  bool OnPgmInit();
65 
66  void OnPgmExit()
67  {
68  Kiway.OnKiwayEnd();
69 
71 
72  // Destroy everything in PGM_BASE, especially wxSingleInstanceCheckerImpl
73  // earlier than wxApp and earlier than static destruction would.
75  }
76 
77  void MacOpenFile( const wxString& aFileName ) override
78  {
79  wxFileName filename( aFileName );
80 
81  if( filename.FileExists() )
82  {
83  #if 0
84  // this pulls in EDA_DRAW_FRAME type info, which we don't want in
85  // the single_top link image.
86  KIWAY_PLAYER* frame = dynamic_cast<KIWAY_PLAYER*>( App().GetTopWindow() );
87  #else
88  KIWAY_PLAYER* frame = (KIWAY_PLAYER*) App().GetTopWindow();
89  #endif
90  if( frame )
91  frame->OpenProjectFiles( std::vector<wxString>( 1, aFileName ) );
92  }
93  }
94 
95 } program;
96 
97 
99 {
100  return program;
101 }
102 
103 // A module to allow Html modules initialization/cleanup
104 // When a wxHtmlWindow is used *only* in a dll/so module, the Html text is displayed
105 // as plain text.
106 // This helper class is just used to force wxHtmlWinParser initialization
107 // see https://groups.google.com/forum/#!topic/wx-users/FF0zv5qGAT0
108 class HtmlModule: public wxModule
109 {
110 public:
112  virtual bool OnInit() override { AddDependency( CLASSINFO( wxHtmlWinParser ) ); return true; };
113  virtual void OnExit() override {};
114 private:
115  wxDECLARE_DYNAMIC_CLASS( HtmlModule );
116 };
118 
124 struct APP_SINGLE_TOP : public wxApp
125 {
126 #if defined (__LINUX__)
127  APP_SINGLE_TOP(): wxApp()
128  {
129  // Disable proxy menu in Unity window manager. Only usual menubar works with wxWidgets (at least <= 3.1)
130  // When the proxy menu menubar is enable, some important things for us do not work: menuitems UI events and shortcuts.
131  wxString wm;
132 
133  if( wxGetEnv( wxT( "XDG_CURRENT_DESKTOP" ), &wm ) && wm.CmpNoCase( wxT( "Unity" ) ) == 0 )
134  {
135  wxSetEnv ( wxT("UBUNTU_MENUPROXY" ), wxT( "0" ) );
136  }
137  }
138 #endif
139 
140  bool OnInit() override
141  {
142  // Force wxHtmlWinParser initialization when a wxHtmlWindow is used only
143  // in a shared modules (.so or .dll file)
144  // Otherwise the Html text is displayed as plain text.
145  HtmlModule html_init;
146 
147  try
148  {
149  return program.OnPgmInit();
150  }
151  catch( const std::exception& e )
152  {
153  wxLogError( wxT( "Unhandled exception class: %s what: %s" ),
154  GetChars( FROM_UTF8( typeid(e).name() )),
155  GetChars( FROM_UTF8( e.what() ) ) );
156  }
157  catch( const IO_ERROR& ioe )
158  {
159  wxLogError( GetChars( ioe.What() ) );
160  }
161  catch(...)
162  {
163  wxLogError( wxT( "Unhandled exception of unknown type" ) );
164  }
165 
166  program.OnPgmExit();
167 
168  return false;
169  }
170 
171  int OnExit() override
172  {
173  // Fixes segfault when wxPython scripting is enabled.
174 #if defined( KICAD_SCRIPTING_WXPYTHON )
175  program.OnPgmExit();
176 #endif
177  return wxApp::OnExit();
178  }
179 
180  int OnRun() override
181  {
182  int ret = -1;
183 
184  try
185  {
186  ret = wxApp::OnRun();
187  }
188  catch( const std::exception& e )
189  {
190  wxLogError( wxT( "Unhandled exception class: %s what: %s" ),
191  GetChars( FROM_UTF8( typeid(e).name() )),
192  GetChars( FROM_UTF8( e.what() ) ) );
193  }
194  catch( const IO_ERROR& ioe )
195  {
196  wxLogError( GetChars( ioe.What() ) );
197  }
198  catch(...)
199  {
200  wxLogError( wxT( "Unhandled exception of unknown type" ) );
201  }
202 
203  // Works properly when wxPython scripting is disabled.
204 #if !defined( KICAD_SCRIPTING_WXPYTHON )
205  program.OnPgmExit();
206 #endif
207  return ret;
208  }
209 
210 
211 #if defined( DEBUG )
212 
219  virtual bool OnExceptionInMainLoop() override
220  {
221  try
222  {
223  throw;
224  }
225  catch( const std::exception& e )
226  {
227  wxLogError( "Unhandled exception class: %s what: %s",
228  FROM_UTF8( typeid(e).name() ),
229  FROM_UTF8( e.what() ) );
230  }
231  catch( const IO_ERROR& ioe )
232  {
233  wxLogError( ioe.What() );
234  }
235  catch(...)
236  {
237  wxLogError( "Unhandled exception of unknown type" );
238  }
239 
240  return false; // continue on. Return false to abort program
241  }
242 #endif
243 
244 #ifdef __WXMAC__
245 
252  void MacOpenFile( const wxString& aFileName ) override
253  {
254  Pgm().MacOpenFile( aFileName );
255  }
256 
257 #endif
258 };
259 
260 IMPLEMENT_APP( APP_SINGLE_TOP )
261 
262 
264 {
265 #if defined(DEBUG)
266  wxString absoluteArgv0 = wxStandardPaths::Get().GetExecutablePath();
267 
268  if( !wxIsAbsolutePath( absoluteArgv0 ) )
269  {
270  wxLogError( wxT( "No meaningful argv[0]" ) );
271  return false;
272  }
273 #endif
274 
275  if( !InitPgm() )
276  return false;
277 
278 #if !defined(BUILD_KIWAY_DLL)
279 
280  // Only bitmap2component and pcb_calculator use this code currently, as they
281  // are not split to use single_top as a link image separate from a *.kiface.
282  // i.e. they are single part link images so don't need to load a *.kiface.
283 
284  // Get the getter, it is statically linked into this binary image.
286 
287  int kiface_version;
288 
289  // Get the KIFACE.
290  KIFACE* kiface = getter( &kiface_version, KIFACE_VERSION, this );
291 
292  // Trick the KIWAY into thinking it loaded a KIFACE, by recording the KIFACE
293  // in the KIWAY. It needs to be there for KIWAY::OnKiwayEnd() anyways.
294  Kiway.set_kiface( KIWAY::KifaceType( TOP_FRAME ), kiface );
295 #endif
296 
297  // Open project or file specified on the command line:
298  int argc = App().argc;
299 
300  int args_offset = 1;
301 
302  FRAME_T appType = TOP_FRAME;
303 
304  const struct
305  {
306  wxString name;
307  FRAME_T type;
308  } frameTypes[] = {
309  { wxT( "pcb" ), FRAME_PCB },
310  { wxT( "fpedit" ), FRAME_PCB_MODULE_EDITOR },
311  { wxT( "" ), FRAME_T_COUNT }
312  };
313 
314  if( argc > 2 )
315  {
316  if( App().argv[1] == "--frame" )
317  {
318  wxString appName = App().argv[2];
319  appType = FRAME_T_COUNT;
320 
321  for( int i = 0; frameTypes[i].type != FRAME_T_COUNT; i++ )
322  {
323  const auto& frame = frameTypes[i];
324  if(frame.name == appName)
325  {
326  appType = frame.type;
327  }
328  }
329  args_offset += 2;
330 
331  if( appType == FRAME_T_COUNT )
332  {
333  wxLogError( wxT( "Unknown frame: %s" ), appName );
334  return false;
335  }
336  }
337  }
338 
339 
340  // Use KIWAY to create a top window, which registers its existence also.
341  // "TOP_FRAME" is a macro that is passed on compiler command line from CMake,
342  // and is one of the types in FRAME_T.
343  KIWAY_PLAYER* frame = Kiway.Player( appType, true );
344 
345  Kiway.SetTop( frame );
346 
347  App().SetTopWindow( frame ); // wxApp gets a face.
348 
349 
350  if( argc > args_offset )
351  {
352  /*
353  gerbview handles multiple project data files, i.e. gerber files on
354  cmd line. Others currently do not, they handle only one. For common
355  code simplicity we simply pass all the arguments in however, each
356  program module can do with them what they want, ignore, complain
357  whatever. We don't establish policy here, as this is a multi-purpose
358  launcher.
359  */
360 
361  std::vector<wxString> argSet;
362 
363  for( int i = args_offset; i < argc; ++i )
364  {
365  argSet.push_back( App().argv[i] );
366  }
367 
368  // special attention to a single argument: argv[1] (==argSet[0])
369  if( argc == args_offset + 1 )
370  {
371  wxFileName argv1( argSet[0] );
372 
373 #if defined(PGM_DATA_FILE_EXT)
374  // PGM_DATA_FILE_EXT, if present, may be different for each compile,
375  // it may come from CMake on the compiler command line, but often does not.
376  // This facillity is mostly useful for those program modules
377  // supporting a single argv[1].
378  if( !argv1.GetExt() )
379  argv1.SetExt( wxT( PGM_DATA_FILE_EXT ) );
380 #endif
381  argv1.MakeAbsolute();
382 
383  argSet[0] = argv1.GetFullPath();
384  }
385 
386  // Use the KIWAY_PLAYER::OpenProjectFiles() API function:
387  if( !frame->OpenProjectFiles( argSet ) )
388  {
389  // OpenProjectFiles() API asks that it report failure to the UI.
390  // Nothing further to say here.
391 
392  // We've already initialized things at this point, but wx won't call OnExit if
393  // we fail out. Call our own cleanup routine here to ensure the relevant resources
394  // are freed at the right time (if they aren't, segfaults will occur).
395  OnPgmExit();
396 
397  // Fail the process startup if the file could not be opened,
398  // although this is an optional choice, one that can be reversed
399  // also in the KIFACE specific OpenProjectFiles() return value.
400  return false;
401  }
402  }
403 
404  frame->Show();
405 
406  return true;
407 }
int OnRun() override
Definition: single_top.cpp:180
Class KIWAY_PLAYER is a wxFrame capable of the OpenProjectFiles function, meaning it can load a porti...
Definition: kiway_player.h:120
void MacOpenFile(const wxString &aFileName) override
Function MacOpenFile is specific to MacOSX (not used under Linux or Windows).
Definition: single_top.cpp:77
int OnExit() override
Definition: single_top.cpp:171
Struct PGM_SINGLE_TOP implements PGM_BASE with its own OnPgmInit() and OnPgmExit().
Definition: single_top.cpp:62
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:98
static wxString FROM_UTF8(const char *cstring)
function FROM_UTF8 converts a UTF8 encoded C string to a wxString for all wxWidgets build modes...
Definition: macros.h:53
static FACE_T KifaceType(FRAME_T aFrameType)
Function KifaceType is a simple mapping function which returns the FACE_T which is known to implement...
Definition: kiway.cpp:250
void OnPgmExit()
Definition: single_top.cpp:66
This file is part of the common library.
void SaveCommonSettings()
Function saveCommonSettings saves the program (process) settings subset which are stored ...
Definition: pgm_base.cpp:628
Class PGM_BASE keeps program (whole process) data for KiCad programs.
Definition: pgm_base.h:149
#define KIFACE_VERSION
Definition: kiway.h:111
FRAME_T
Enum FRAME_T is the set of EDA_BASE_FRAME derivatives, typically stored in EDA_BASE_FRAME::m_Ident.
Definition: frame_type.h:34
VTBL_ENTRY wxApp & App()
Function App returns a bare naked wxApp, which may come from wxPython, SINGLE_TOP, or kicad.exe.
Definition: pgm_base.cpp:188
void Destroy()
Definition: pgm_base.cpp:173
void OnKiwayEnd()
Definition: kiway.cpp:482
bool OnInit() override
Definition: single_top.cpp:140
VTBL_ENTRY bool OpenProjectFiles(const std::vector< wxString > &aFileList, int aCtl=0)
Function OpenProjectFiles is abstract, and opens a project or set of files given by aFileList...
Definition: kiway_player.h:179
This file contains miscellaneous commonly used macros and functions.
bool set_kiface(FACE_T aFaceType, KIFACE *aKiface)
Definition: kiway.h:396
VTBL_ENTRY KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=NULL)
Function Player returns the KIWAY_PLAYER* given a FRAME_T.
Definition: kiway.cpp:300
KIFACE * KIFACE_GETTER(int *aKIFACEversion, int aKIWAYversion, PGM_BASE *aProgram)
No name mangling. Each KIFACE (DSO/DLL) will implement this once.
KIFACE * KIFACE_GETTER_FUNC(int *aKIFACEversion, int aKIWAYversion, PGM_BASE *aProgram)
Function Pointer KIFACE_GETTER_FUNC points to the one and only KIFACE export.
Definition: kiway.h:452
virtual bool OnInit() override
Definition: single_top.cpp:112
virtual void OnExit() override
Definition: single_top.cpp:113
Class KIWAY is a minimalistic software bus for communications between various DLLs/DSOs (DSOs) within...
Definition: kiway.h:258
wxIMPLEMENT_DYNAMIC_CLASS(HtmlModule, wxModule)
void SetTop(wxFrame *aTop)
Function SetTop tells this KIWAY about the top most frame in the program and optionally allows it to ...
Definition: kiway.cpp:76
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:33
static const wxChar * GetChars(const wxString &s)
Function GetChars returns a wxChar* to the actual wxChar* data within a wxString, and is helpful for ...
Definition: macros.h:92
see class PGM_BASE
const char * name
Definition: DXF_plotter.cpp:61
PGM_SINGLE_TOP program
size_t i
Definition: json11.cpp:597
Class KIFACE is used by a participant in the KIWAY alchemy.
Definition: kiway.h:151
bool InitPgm()
Function initPgm initializes this program (process) in a KiCad standard way, using some generalized t...
Definition: pgm_base.cpp:263
return & kiface
Definition: pcbnew.cpp:219
Struct IO_ERROR is a class used to hold an error message and may be used when throwing exceptions con...
Definition: ki_exception.h:76
Struct APP_SINGLE_TOP implements a bare naked wxApp (so that we don&#39;t become dependent on functionali...
Definition: single_top.cpp:124
#define KFCTL_STANDALONE
Am running as a standalone Top.
Definition: kiway.h:159
KIWAY Kiway