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