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