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/cmdline.h>
41 #include <wx/filename.h>
42 #include <wx/stdpaths.h>
43 #include <wx/snglinst.h>
44 #include <wx/html/htmlwin.h>
45 
46 #include <kiway.h>
47 #include <pgm_base.h>
48 #include <kiway_player.h>
49 #include <confirm.h>
51 
52 
53 // Only a single KIWAY is supported in this single_top top level component,
54 // which is dedicated to loading only a single DSO.
56 
57 
58 // implement a PGM_BASE and a wxApp side by side:
59 
64 static struct PGM_SINGLE_TOP : public PGM_BASE
65 {
66  bool OnPgmInit();
67 
68  void OnPgmExit()
69  {
70  Kiway.OnKiwayEnd();
71 
72  if( m_settings_manager && m_settings_manager->IsOK() )
73  {
75  m_settings_manager->Save();
76  }
77 
78  // Destroy everything in PGM_BASE, especially wxSingleInstanceCheckerImpl
79  // earlier than wxApp and earlier than static destruction would.
81  }
82 
83  void MacOpenFile( const wxString& aFileName ) override
84  {
85  wxFileName filename( aFileName );
86 
87  if( filename.FileExists() )
88  {
89  #if 0
90  // this pulls in EDA_DRAW_FRAME type info, which we don't want in
91  // the single_top link image.
92  KIWAY_PLAYER* frame = dynamic_cast<KIWAY_PLAYER*>( App().GetTopWindow() );
93  #else
94  KIWAY_PLAYER* frame = (KIWAY_PLAYER*) App().GetTopWindow();
95  #endif
96  if( frame )
97  frame->OpenProjectFiles( std::vector<wxString>( 1, aFileName ) );
98  }
99  }
100 
101 } program;
102 
103 
105 {
106  return program;
107 }
108 
109 // A module to allow Html modules initialization/cleanup
110 // When a wxHtmlWindow is used *only* in a dll/so module, the Html text is displayed
111 // as plain text.
112 // This helper class is just used to force wxHtmlWinParser initialization
113 // see https://groups.google.com/forum/#!topic/wx-users/FF0zv5qGAT0
114 class HtmlModule: public wxModule
115 {
116 public:
118  virtual bool OnInit() override { AddDependency( CLASSINFO( wxHtmlWinParser ) ); return true; };
119  virtual void OnExit() override {};
120 private:
122 };
124 
130 struct APP_SINGLE_TOP : public wxApp
131 {
132 #if defined (__LINUX__)
133  APP_SINGLE_TOP(): wxApp()
134  {
135  // Disable proxy menu in Unity window manager. Only usual menubar works with wxWidgets (at least <= 3.1)
136  // When the proxy menu menubar is enable, some important things for us do not work: menuitems UI events and shortcuts.
137  wxString wm;
138 
139  if( wxGetEnv( wxT( "XDG_CURRENT_DESKTOP" ), &wm ) && wm.CmpNoCase( wxT( "Unity" ) ) == 0 )
140  {
141  wxSetEnv ( wxT("UBUNTU_MENUPROXY" ), wxT( "0" ) );
142  }
143 
144  // Force the use of X11 backend (or wayland-x11 compatibilty layer). This is required until wxWidgets
145  // supports the Wayland compositors
146  wxSetEnv( wxT( "GDK_BACKEND" ), wxT( "x11" ) );
147 
148  // Disable overlay scrollbars as they mess up wxWidgets window sizing and cause excessive redraw requests
149  wxSetEnv( wxT( "GTK_OVERLAY_SCROLLING" ), wxT( "0" ) );
150 
151  // Set GTK2-style input instead of xinput2. This disables touchscreen and smooth scrolling
152  // Needed to ensure that we are not getting multiple mouse scroll events
153  wxSetEnv( wxT( "GDK_CORE_DEVICE_EVENTS" ), wxT( "1" ) );
154  }
155 #endif
156 
157  bool OnInit() override
158  {
159  // Force wxHtmlWinParser initialization when a wxHtmlWindow is used only
160  // in a shared modules (.so or .dll file)
161  // Otherwise the Html text is displayed as plain text.
162  HtmlModule html_init;
163 
164  try
165  {
166  if( !program.OnPgmInit() )
167  {
168  program.OnPgmExit();
169  return false;
170  }
171 
172  return true;
173  }
174  catch( const std::exception& e )
175  {
176  wxLogError( wxT( "Unhandled exception class: %s what: %s" ),
177  GetChars( FROM_UTF8( typeid(e).name() )),
178  GetChars( FROM_UTF8( e.what() ) ) );
179  }
180  catch( const IO_ERROR& ioe )
181  {
182  wxLogError( GetChars( ioe.What() ) );
183  }
184  catch(...)
185  {
186  wxLogError( wxT( "Unhandled exception of unknown type" ) );
187  }
188 
189  program.OnPgmExit();
190 
191  return false;
192  }
193 
194  int OnExit() override
195  {
196  // Fixes segfault when wxPython scripting is enabled.
197 #if defined( KICAD_SCRIPTING_WXPYTHON )
198  program.OnPgmExit();
199 #endif
200  return wxApp::OnExit();
201  }
202 
203  int OnRun() override
204  {
205  int ret = -1;
206 
207  try
208  {
209  ret = wxApp::OnRun();
210  }
211  catch( const std::exception& e )
212  {
213  wxLogError( wxT( "Unhandled exception class: %s what: %s" ),
214  GetChars( FROM_UTF8( typeid(e).name() )),
215  GetChars( FROM_UTF8( e.what() ) ) );
216  }
217  catch( const IO_ERROR& ioe )
218  {
219  wxLogError( GetChars( ioe.What() ) );
220  }
221  catch(...)
222  {
223  wxLogError( wxT( "Unhandled exception of unknown type" ) );
224  }
225 
226  // Works properly when wxPython scripting is disabled.
227 #if !defined( KICAD_SCRIPTING_WXPYTHON )
228  program.OnPgmExit();
229 #endif
230  return ret;
231  }
232 
233 
234 #if defined( DEBUG )
235 
242  virtual bool OnExceptionInMainLoop() override
243  {
244  try
245  {
246  throw;
247  }
248  catch( const std::exception& e )
249  {
250  wxLogError( "Unhandled exception class: %s what: %s",
251  FROM_UTF8( typeid(e).name() ),
252  FROM_UTF8( e.what() ) );
253  }
254  catch( const IO_ERROR& ioe )
255  {
256  wxLogError( ioe.What() );
257  }
258  catch(...)
259  {
260  wxLogError( "Unhandled exception of unknown type" );
261  }
262 
263  return false; // continue on. Return false to abort program
264  }
265 #endif
266 
267 #ifdef __WXMAC__
268 
275  void MacOpenFile( const wxString& aFileName ) override
276  {
277  Pgm().MacOpenFile( aFileName );
278  }
279 
280 #endif
281 };
282 
283 IMPLEMENT_APP( APP_SINGLE_TOP )
284 
285 
286 bool PGM_SINGLE_TOP::OnPgmInit()
287 {
288 #if defined(DEBUG)
289  wxString absoluteArgv0 = wxStandardPaths::Get().GetExecutablePath();
290 
291  if( !wxIsAbsolutePath( absoluteArgv0 ) )
292  {
293  wxLogError( wxT( "No meaningful argv[0]" ) );
294  return false;
295  }
296 #endif
297 
298  if( !InitPgm() )
299  return false;
300 
301 #if !defined(BUILD_KIWAY_DLL)
302 
303  // Only bitmap2component and pcb_calculator use this code currently, as they
304  // are not split to use single_top as a link image separate from a *.kiface.
305  // i.e. they are single part link images so don't need to load a *.kiface.
306 
307  // Get the getter, it is statically linked into this binary image.
309 
310  int kiface_version;
311 
312  // Get the KIFACE.
313  KIFACE* kiface = getter( &kiface_version, KIFACE_VERSION, this );
314 
315  // Trick the KIWAY into thinking it loaded a KIFACE, by recording the KIFACE
316  // in the KIWAY. It needs to be there for KIWAY::OnKiwayEnd() anyways.
317  Kiway.set_kiface( KIWAY::KifaceType( TOP_FRAME ), kiface );
318 #endif
319 
320  static const wxCmdLineEntryDesc desc[] = {
321  { wxCMD_LINE_OPTION, "f", "frame", "Frame to load", wxCMD_LINE_VAL_STRING, 0 },
322  { wxCMD_LINE_PARAM, nullptr, nullptr, "File to load", wxCMD_LINE_VAL_STRING,
323  wxCMD_LINE_PARAM_MULTIPLE | wxCMD_LINE_PARAM_OPTIONAL },
324  { wxCMD_LINE_NONE, nullptr, nullptr, nullptr, wxCMD_LINE_VAL_NONE, 0 }
325  };
326 
327  wxCmdLineParser parser( App().argc, App().argv );
328  parser.SetDesc( desc );
329  parser.Parse( false );
330 
331  FRAME_T appType = TOP_FRAME;
332 
333  const struct
334  {
335  wxString name;
336  FRAME_T type;
337  } frameTypes[] = {
338  { wxT( "pcb" ), FRAME_PCB_EDITOR },
339  { wxT( "fpedit" ), FRAME_FOOTPRINT_EDITOR },
340  { wxT( "" ), FRAME_T_COUNT }
341  };
342 
343  wxString frameName;
344 
345  if( parser.Found( "frame", &frameName ) )
346  {
347  appType = FRAME_T_COUNT;
348 
349  for( const auto& it : frameTypes )
350  {
351  if( it.name == frameName )
352  appType = it.type;
353  }
354 
355  if( appType == FRAME_T_COUNT )
356  {
357  wxLogError( wxT( "Unknown frame: %s" ), frameName );
358  return false;
359  }
360  }
361 
362 
363  // Use KIWAY to create a top window, which registers its existence also.
364  // "TOP_FRAME" is a macro that is passed on compiler command line from CMake,
365  // and is one of the types in FRAME_T.
366  KIWAY_PLAYER* frame = Kiway.Player( appType, true );
367 
368  Kiway.SetTop( frame );
369 
370  App().SetTopWindow( frame ); // wxApp gets a face.
371 
372  // Individual frames may provide additional option/switch processing, but for compatibility,
373  // any positional arguments are treated as a list of files to pass to OpenProjectFiles
374  frame->ParseArgs( parser );
375 
376  // Now after the frame processing, the rest of the positional args are files
377  std::vector<wxString> fileArgs;
378 
379  if( parser.GetParamCount() )
380  {
381  /*
382  gerbview handles multiple project data files, i.e. gerber files on
383  cmd line. Others currently do not, they handle only one. For common
384  code simplicity we simply pass all the arguments in however, each
385  program module can do with them what they want, ignore, complain
386  whatever. We don't establish policy here, as this is a multi-purpose
387  launcher.
388  */
389 
390  for( size_t i = 0; i < parser.GetParamCount(); i++ )
391  fileArgs.push_back( parser.GetParam( i ) );
392 
393  // special attention to a single argument: argv[1] (==argSet[0])
394  if( fileArgs.size() == 1 )
395  {
396  wxFileName argv1( fileArgs[0] );
397 
398 #if defined(PGM_DATA_FILE_EXT)
399  // PGM_DATA_FILE_EXT, if present, may be different for each compile,
400  // it may come from CMake on the compiler command line, but often does not.
401  // This facility is mostly useful for those program modules
402  // supporting a single argv[1].
403  if( !argv1.GetExt() )
404  argv1.SetExt( wxT( PGM_DATA_FILE_EXT ) );
405 #endif
406  argv1.MakeAbsolute();
407 
408  fileArgs[0] = argv1.GetFullPath();
409  }
410 
411  // Use the KIWAY_PLAYER::OpenProjectFiles() API function:
412  if( !frame->OpenProjectFiles( fileArgs ) )
413  {
414  // OpenProjectFiles() API asks that it report failure to the UI.
415  // Nothing further to say here.
416 
417  // We've already initialized things at this point, but wx won't call OnExit if
418  // we fail out. Call our own cleanup routine here to ensure the relevant resources
419  // are freed at the right time (if they aren't, segfaults will occur).
420  OnPgmExit();
421 
422  // Fail the process startup if the file could not be opened,
423  // although this is an optional choice, one that can be reversed
424  // also in the KIFACE specific OpenProjectFiles() return value.
425  return false;
426  }
427  }
428 
429  frame->Show();
430 
431  return true;
432 }
int OnRun() override
Definition: single_top.cpp:203
virtual 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:118
BITMAP2CMP_SETTINGS kiface
KIWAY_PLAYER is a wxFrame capable of the OpenProjectFiles function, meaning it can load a portion of ...
Definition: kiway_player.h:59
void MacOpenFile(const wxString &aFileName) override
Function MacOpenFile is specific to MacOSX (not used under Linux or Windows).
Definition: single_top.cpp:83
int OnExit() override
Definition: single_top.cpp:194
Struct PGM_SINGLE_TOP implements PGM_BASE with its own OnPgmInit() and OnPgmExit().
Definition: single_top.cpp:64
KIWAY Kiway & Pgm(), KFCTL_STANDALONE
The global Program "get" accessor.
Definition: single_top.cpp:104
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:114
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:292
void OnPgmExit()
Definition: single_top.cpp:68
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:524
PGM_BASE keeps program (whole process) data for KiCad programs.
Definition: pgm_base.h:137
#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
wxDECLARE_DYNAMIC_CLASS(HtmlModule)
VTBL_ENTRY wxApp & App()
Function App returns a bare naked wxApp, which may come from wxPython, SINGLE_TOP,...
Definition: pgm_base.cpp:138
void Destroy()
Definition: pgm_base.cpp:127
void OnKiwayEnd()
Definition: kiway.cpp:538
bool OnInit() override
Definition: single_top.cpp:157
This file contains miscellaneous commonly used macros and functions.
bool set_kiface(FACE_T aFaceType, KIFACE *aKiface)
Definition: kiway.h:413
std::unique_ptr< SETTINGS_MANAGER > m_settings_manager
Definition: pgm_base.h:348
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:342
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:33
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:467
virtual bool OnInit() override
Definition: single_top.cpp:118
virtual void OnExit() override
Definition: single_top.cpp:119
KIWAY is a minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the s...
Definition: kiway.h:273
#define KIFACE_GETTER
Definition: kiway.h:112
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:78
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:153
see class PGM_BASE
const char * name
Definition: DXF_plotter.cpp:60
VTBL_ENTRY const wxString & GetExecutablePath() const
Definition: pgm_base.h:205
PGM_SINGLE_TOP program
KIFACE is used by a participant in the KIWAY alchemy.
Definition: kiway.h:150
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
virtual void ParseArgs(wxCmdLineParser &aParser)
Handles command-line arguments in a frame-specific way.
Definition: kiway_player.h:138
Struct APP_SINGLE_TOP implements a bare naked wxApp (so that we don't become dependent on functionali...
Definition: single_top.cpp:130
#define KFCTL_STANDALONE
Am running as a standalone Top.
Definition: kiway.h:158
KIWAY Kiway