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