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:
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  // Force the use of X11 backend (or wayland-x11 compatibilty layer). This is required until wxWidgets
139  // supports the Wayland compositors
140  wxSetEnv( wxT( "GDK_BACKEND" ), wxT( "x11" ) );
141 
142  // Disable overlay scrollbars as they mess up wxWidgets window sizing and cause excessive redraw requests
143  wxSetEnv( wxT( "GTK_OVERLAY_SCROLLING" ), wxT( "0" ) );
144 
145  // Set GTK2-style input instead of xinput2. This disables touchscreen and smooth scrolling
146  // Needed to ensure that we are not getting multiple mouse scroll events
147  wxSetEnv( wxT( "GDK_CORE_DEVICE_EVENTS" ), wxT( "1" ) );
148  }
149 #endif
150 
151  bool OnInit() override
152  {
153  // Force wxHtmlWinParser initialization when a wxHtmlWindow is used only
154  // in a shared modules (.so or .dll file)
155  // Otherwise the Html text is displayed as plain text.
156  HtmlModule html_init;
157 
158  try
159  {
160  return program.OnPgmInit();
161  }
162  catch( const std::exception& e )
163  {
164  wxLogError( wxT( "Unhandled exception class: %s what: %s" ),
165  GetChars( FROM_UTF8( typeid(e).name() )),
166  GetChars( FROM_UTF8( e.what() ) ) );
167  }
168  catch( const IO_ERROR& ioe )
169  {
170  wxLogError( GetChars( ioe.What() ) );
171  }
172  catch(...)
173  {
174  wxLogError( wxT( "Unhandled exception of unknown type" ) );
175  }
176 
177  program.OnPgmExit();
178 
179  return false;
180  }
181 
182  int OnExit() override
183  {
184  // Fixes segfault when wxPython scripting is enabled.
185 #if defined( KICAD_SCRIPTING_WXPYTHON )
186  program.OnPgmExit();
187 #endif
188  return wxApp::OnExit();
189  }
190 
191  int OnRun() override
192  {
193  int ret = -1;
194 
195  try
196  {
197  ret = wxApp::OnRun();
198  }
199  catch( const std::exception& e )
200  {
201  wxLogError( wxT( "Unhandled exception class: %s what: %s" ),
202  GetChars( FROM_UTF8( typeid(e).name() )),
203  GetChars( FROM_UTF8( e.what() ) ) );
204  }
205  catch( const IO_ERROR& ioe )
206  {
207  wxLogError( GetChars( ioe.What() ) );
208  }
209  catch(...)
210  {
211  wxLogError( wxT( "Unhandled exception of unknown type" ) );
212  }
213 
214  // Works properly when wxPython scripting is disabled.
215 #if !defined( KICAD_SCRIPTING_WXPYTHON )
216  program.OnPgmExit();
217 #endif
218  return ret;
219  }
220 
221 
222 #if defined( DEBUG )
223 
230  virtual bool OnExceptionInMainLoop() override
231  {
232  try
233  {
234  throw;
235  }
236  catch( const std::exception& e )
237  {
238  wxLogError( "Unhandled exception class: %s what: %s",
239  FROM_UTF8( typeid(e).name() ),
240  FROM_UTF8( e.what() ) );
241  }
242  catch( const IO_ERROR& ioe )
243  {
244  wxLogError( ioe.What() );
245  }
246  catch(...)
247  {
248  wxLogError( "Unhandled exception of unknown type" );
249  }
250 
251  return false; // continue on. Return false to abort program
252  }
253 #endif
254 
255 #ifdef __WXMAC__
256 
263  void MacOpenFile( const wxString& aFileName ) override
264  {
265  Pgm().MacOpenFile( aFileName );
266  }
267 
268 #endif
269 };
270 
271 IMPLEMENT_APP( APP_SINGLE_TOP )
272 
273 
274 bool PGM_SINGLE_TOP::OnPgmInit()
275 {
276 #if defined(DEBUG)
277  wxString absoluteArgv0 = wxStandardPaths::Get().GetExecutablePath();
278 
279  if( !wxIsAbsolutePath( absoluteArgv0 ) )
280  {
281  wxLogError( wxT( "No meaningful argv[0]" ) );
282  return false;
283  }
284 #endif
285 
286  if( !InitPgm() )
287  return false;
288 
289 #if !defined(BUILD_KIWAY_DLL)
290 
291  // Only bitmap2component and pcb_calculator use this code currently, as they
292  // are not split to use single_top as a link image separate from a *.kiface.
293  // i.e. they are single part link images so don't need to load a *.kiface.
294 
295  // Get the getter, it is statically linked into this binary image.
297 
298  int kiface_version;
299 
300  // Get the KIFACE.
301  KIFACE* kiface = getter( &kiface_version, KIFACE_VERSION, this );
302 
303  // Trick the KIWAY into thinking it loaded a KIFACE, by recording the KIFACE
304  // in the KIWAY. It needs to be there for KIWAY::OnKiwayEnd() anyways.
305  Kiway.set_kiface( KIWAY::KifaceType( TOP_FRAME ), kiface );
306 #endif
307 
308  // Open project or file specified on the command line:
309  int argc = App().argc;
310 
311  int args_offset = 1;
312 
313  FRAME_T appType = TOP_FRAME;
314 
315  const struct
316  {
317  wxString name;
318  FRAME_T type;
319  } frameTypes[] = {
320  { wxT( "pcb" ), FRAME_PCB },
321  { wxT( "fpedit" ), FRAME_PCB_MODULE_EDITOR },
322  { wxT( "" ), FRAME_T_COUNT }
323  };
324 
325  if( argc > 2 )
326  {
327  if( App().argv[1] == "--frame" )
328  {
329  wxString appName = App().argv[2];
330  appType = FRAME_T_COUNT;
331 
332  for( int i = 0; frameTypes[i].type != FRAME_T_COUNT; i++ )
333  {
334  const auto& frame = frameTypes[i];
335  if(frame.name == appName)
336  {
337  appType = frame.type;
338  }
339  }
340  args_offset += 2;
341 
342  if( appType == FRAME_T_COUNT )
343  {
344  wxLogError( wxT( "Unknown frame: %s" ), appName );
345  return false;
346  }
347  }
348  }
349 
350 
351  // Use KIWAY to create a top window, which registers its existence also.
352  // "TOP_FRAME" is a macro that is passed on compiler command line from CMake,
353  // and is one of the types in FRAME_T.
354  KIWAY_PLAYER* frame = Kiway.Player( appType, true );
355 
356  Kiway.SetTop( frame );
357 
358  App().SetTopWindow( frame ); // wxApp gets a face.
359 
360 
361  if( argc > args_offset )
362  {
363  /*
364  gerbview handles multiple project data files, i.e. gerber files on
365  cmd line. Others currently do not, they handle only one. For common
366  code simplicity we simply pass all the arguments in however, each
367  program module can do with them what they want, ignore, complain
368  whatever. We don't establish policy here, as this is a multi-purpose
369  launcher.
370  */
371 
372  std::vector<wxString> argSet;
373 
374  for( int i = args_offset; i < argc; ++i )
375  {
376  argSet.push_back( App().argv[i] );
377  }
378 
379  // special attention to a single argument: argv[1] (==argSet[0])
380  if( argc == args_offset + 1 )
381  {
382  wxFileName argv1( argSet[0] );
383 
384 #if defined(PGM_DATA_FILE_EXT)
385  // PGM_DATA_FILE_EXT, if present, may be different for each compile,
386  // it may come from CMake on the compiler command line, but often does not.
387  // This facillity is mostly useful for those program modules
388  // supporting a single argv[1].
389  if( !argv1.GetExt() )
390  argv1.SetExt( wxT( PGM_DATA_FILE_EXT ) );
391 #endif
392  argv1.MakeAbsolute();
393 
394  argSet[0] = argv1.GetFullPath();
395  }
396 
397  // Use the KIWAY_PLAYER::OpenProjectFiles() API function:
398  if( !frame->OpenProjectFiles( argSet ) )
399  {
400  // OpenProjectFiles() API asks that it report failure to the UI.
401  // Nothing further to say here.
402 
403  // We've already initialized things at this point, but wx won't call OnExit if
404  // we fail out. Call our own cleanup routine here to ensure the relevant resources
405  // are freed at the right time (if they aren't, segfaults will occur).
406  OnPgmExit();
407 
408  // Fail the process startup if the file could not be opened,
409  // although this is an optional choice, one that can be reversed
410  // also in the KIFACE specific OpenProjectFiles() return value.
411  return false;
412  }
413  }
414 
415  frame->Show();
416 
417  return true;
418 }
int OnRun() override
Definition: single_top.cpp:191
Class KIWAY_PLAYER is a wxFrame capable of the OpenProjectFiles function, meaning it can load a porti...
Definition: kiway_player.h:127
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:182
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:61
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:271
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:643
Class PGM_BASE keeps program (whole process) data for KiCad programs.
Definition: pgm_base.h:152
#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:185
void Destroy()
Definition: pgm_base.cpp:172
void OnKiwayEnd()
Definition: kiway.cpp:502
bool OnInit() override
Definition: single_top.cpp:151
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:186
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:321
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:33
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:77
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:100
see class PGM_BASE
const char * name
Definition: DXF_plotter.cpp:61
VTBL_ENTRY const wxString & GetExecutablePath() const
Definition: pgm_base.h:218
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
return & kiface
Definition: pcbnew.cpp:212
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'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