KiCad PCB EDA Suite
kiway.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-2017 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 #include <cstring>
26 
27 #include <macros.h>
28 #include <kiway.h>
29 #include <kiway_player.h>
30 #include <kiway_express.h>
31 #include <pgm_base.h>
32 #include <config.h>
33 #include <id.h>
34 
35 #include <wx/stdpaths.h>
36 #include <wx/debug.h>
37 #include <wx/utils.h>
38 
39 
40 KIFACE* KIWAY::m_kiface[KIWAY_FACE_COUNT];
41 int KIWAY::m_kiface_version[KIWAY_FACE_COUNT];
42 
43 
44 
45 KIWAY::KIWAY( PGM_BASE* aProgram, int aCtlBits, wxFrame* aTop ):
46  m_program( aProgram ), m_ctl( aCtlBits ), m_top( 0 )
47 {
48  SetTop( aTop ); // hook player_destroy_handler() into aTop.
49 
50 
51  // Prepare the room to store the frame names, once they will be created
52  // with FRAME_T type as index in this table.
53  // (note this is a list of frame names, but a non empty entry
54  // does not mean the frame still exists. It means only the frame was created
55  // at least once. It can be destroyed after. These entries are not cleared.
56  // the purpose is just to allow a call to wxWindow::FindWindowByName(), from
57  // a FRAME_T frame type
58  m_playerFrameName.Add( wxEmptyString, KIWAY_PLAYER_COUNT );
59 }
60 
61 
62 #if 0
63 // Any event types derived from wxCommandEvt, like wxWindowDestroyEvent, are
64 // propagated upwards to parent windows if not handled below. Therefore the
65 // m_top window should receive all wxWindowDestroyEvents originating from
66 // KIWAY_PLAYERs. It does anyways, but now player_destroy_handler eavesdrops
67 // on that event stream looking for KIWAY_PLAYERs being closed.
68 
69 void KIWAY::player_destroy_handler( wxWindowDestroyEvent& event )
70 {
71  // Currently : do nothing
72  event.Skip(); // skip to who, the wxApp? I'm the top window.
73 }
74 #endif
75 
76 
77 void KIWAY::SetTop( wxFrame* aTop )
78 {
79 #if 0
80  if( m_top )
81  {
82  m_top->Disconnect( wxEVT_DESTROY, wxWindowDestroyEventHandler( KIWAY::player_destroy_handler ), NULL, this );
83  }
84 
85  if( aTop )
86  {
87  aTop->Connect( wxEVT_DESTROY, wxWindowDestroyEventHandler( KIWAY::player_destroy_handler ), NULL, this );
88  }
89 #endif
90 
91  m_top = aTop;
92 }
93 
94 
95 const wxString KIWAY::dso_search_path( FACE_T aFaceId )
96 {
97  const char* name;
98 
99  switch( aFaceId )
100  {
101  case FACE_SCH: name = KIFACE_PREFIX "eeschema"; break;
102  case FACE_PCB: name = KIFACE_PREFIX "pcbnew"; break;
103  case FACE_CVPCB: name = KIFACE_PREFIX "cvpcb"; break;
104  case FACE_GERBVIEW: name = KIFACE_PREFIX "gerbview"; break;
105  case FACE_PL_EDITOR: name = KIFACE_PREFIX "pl_editor"; break;
106  case FACE_PCB_CALCULATOR: name = KIFACE_PREFIX "pcb_calculator"; break;
107  case FACE_BMP2CMP: name = KIFACE_PREFIX "bitmap2component"; break;
108 
109  default:
110  wxASSERT_MSG( 0, wxT( "caller has a bug, passed a bad aFaceId" ) );
111  return wxEmptyString;
112  }
113 
114 #ifndef __WXMAC__
115  wxString path;
116 
118  {
119  // The 2 *.cpp program launchers: single_top.cpp and kicad.cpp expect
120  // the *.kiface's to reside in same directory as their binaries do.
121  // Not so for python launcher, identified by KFCTL_PY_PROJECT_SUITE
122  path = wxStandardPaths::Get().GetExecutablePath();
123  }
124 
125  wxFileName fn = path;
126 #else
127  // we have the dso's in main OSX bundle kicad.app/Contents/PlugIns
128  wxFileName fn = Pgm().GetExecutablePath();
129  fn.AppendDir( wxT( "Contents" ) );
130  fn.AppendDir( wxT( "PlugIns" ) );
131 #endif
132 
133  fn.SetName( name );
134 
135 #ifdef DEBUG
136  // To speed up development, it's sometimes nice to run kicad from inside
137  // the build path. In that case, each program will be in a subdirectory.
138  // To find the DSOs, we need to go up one directory and then enter a subdirectory.
139 
140  if( wxGetEnv( wxT( "KICAD_RUN_FROM_BUILD_DIR" ), nullptr ) )
141  {
142 #ifdef __WXMAC__
143  fn = wxStandardPaths::Get().GetExecutablePath();
144  fn.RemoveLastDir();
145  fn.AppendDir( wxT( "PlugIns" ) );
146  fn.SetName( name );
147 #else
148  const char* dirName;
149 
150  // The subdirectories usually have the same name as the kiface
151  switch( aFaceId )
152  {
153  case FACE_PL_EDITOR: dirName = "pagelayout_editor"; break;
154  default: dirName = name + 1; break;
155  }
156 
157  fn.RemoveLastDir();
158  fn.AppendDir( dirName );
159 #endif
160  }
161 #endif
162 
163  // Here a "suffix" == an extension with a preceding '.',
164  // so skip the preceding '.' to get an extension
165  fn.SetExt( KIFACE_SUFFIX + 1 ); // + 1 => &KIFACE_SUFFIX[1]
166 
167  return fn.GetFullPath();
168 }
169 
170 
172 {
173  return *(PROJECT*) &m_project; // strip const-ness, function really is const.
174 }
175 
176 
177 KIFACE* KIWAY::KiFACE( FACE_T aFaceId, bool doLoad )
178 {
179  // Since this will be called from python, cannot assume that code will
180  // not pass a bad aFaceId.
181  if( (unsigned) aFaceId >= arrayDim( m_kiface ) )
182  {
183  // @todo : throw an exception here for python's benefit, at least that
184  // way it gets some explanatory text.
185 
186  wxASSERT_MSG( 0, wxT( "caller has a bug, passed a bad aFaceId" ) );
187  return NULL;
188  }
189 
190  // return the previously loaded KIFACE, if it was.
191  if( m_kiface[aFaceId] )
192  return m_kiface[aFaceId];
193 
194  wxString msg;
195 
196  // DSO with KIFACE has not been loaded yet, does caller want to load it?
197  if( doLoad )
198  {
199  wxString dname = dso_search_path( aFaceId );
200 
201  wxDynamicLibrary dso;
202 
203  void* addr = NULL;
204 
205  // For some reason wxDynamicLibrary::Load() crashes in some languages
206  // (chinese for instance) when loading the dynamic library.
207  // The crash happens for Eeschema.
208  // So switch to "C" locale during loading (LC_COLLATE is enough).
209  int lc_new_type = LC_COLLATE;
210  std::string user_locale = setlocale( lc_new_type, nullptr );
211  setlocale( lc_new_type, "C" );
212 
213  bool success = dso.Load( dname, wxDL_VERBATIM | wxDL_NOW | wxDL_GLOBAL );
214 
215  setlocale( lc_new_type, user_locale.c_str() );
216 
217  if( !success )
218  {
219  // Failure: error reporting UI was done via wxLogSysError().
220  // No further reporting required here. Apparently this is not true on all
221  // platforms and/or wxWidgets builds and KiCad will crash. Throwing the exception
222  // here and catching it in the KiCad launcher resolves the crash issue. See bug
223  // report https://bugs.launchpad.net/kicad/+bug/1577786.
224 
225  msg.Printf( _( "Failed to load kiface library \"%s\"." ), dname );
226  THROW_IO_ERROR( msg );
227  }
228  else if( ( addr = dso.GetSymbol( wxT( KIFACE_INSTANCE_NAME_AND_VERSION ) ) ) == NULL )
229  {
230  // Failure: error reporting UI was done via wxLogSysError().
231  // No further reporting required here. Assume the same thing applies here as
232  // above with the Load() call. This has not been tested.
233  msg.Printf(
234  _( "Could not read instance name and version symbol form kiface library \"%s\"." ),
235  dname );
236  THROW_IO_ERROR( msg );
237  }
238  else
239  {
240  KIFACE_GETTER_FUNC* getter = (KIFACE_GETTER_FUNC*) addr;
241 
242  KIFACE* kiface = getter( &m_kiface_version[aFaceId], KIFACE_VERSION, m_program );
243 
244  // KIFACE_GETTER_FUNC function comment (API) says the non-NULL is unconditional.
245  wxASSERT_MSG( kiface,
246  wxT( "attempted DSO has a bug, failed to return a KIFACE*" ) );
247 
248  // Give the DSO a single chance to do its "process level" initialization.
249  // "Process level" specifically means stay away from any projects in there.
250  if( kiface->OnKifaceStart( m_program, m_ctl ) )
251  {
252  // Tell dso's wxDynamicLibrary destructor not to Unload() the program image.
253  (void) dso.Detach();
254 
255  return m_kiface[aFaceId] = kiface;
256  }
257  }
258 
259  // In any of the failure cases above, dso.Unload() should be called here
260  // by dso destructor.
261  // However:
262 
263  // There is a file installation bug. We only look for KIFACE_I's which we know
264  // to exist, and we did not find one. If we do not find one, this is an
265  // installation bug.
266 
267  msg = wxString::Format( _(
268  "Fatal Installation Bug. File:\n"
269  "\"%s\"\ncould not be loaded\n" ), dname );
270 
271  if( ! wxFileExists( dname ) )
272  msg << _( "It is missing.\n" );
273  else
274  msg << _( "Perhaps a shared library (.dll or .so) file is missing.\n" );
275 
276  msg << _( "From command line: argv[0]:\n'" );
277  msg << wxStandardPaths::Get().GetExecutablePath() << wxT( "'\n" );
278 
279  // This is a fatal error, one from which we cannot recover, nor do we want
280  // to protect against in client code which would require numerous noisy
281  // tests in numerous places. So we inform the user that the installation
282  // is bad. This exception will likely not get caught until way up in the
283  // wxApp derivative, at which point the process will exit gracefully.
284  THROW_IO_ERROR( msg );
285  }
286 
287  return NULL;
288 }
289 
290 
292 {
293  switch( aFrameType )
294  {
295  case FRAME_SCH:
297  case FRAME_SCH_VIEWER:
299  case FRAME_SIMULATOR:
300  return FACE_SCH;
301 
302  case FRAME_PCB_EDITOR:
307  case FRAME_PCB_DISPLAY3D:
308  return FACE_PCB;
309 
310  case FRAME_CVPCB:
311  case FRAME_CVPCB_DISPLAY:
312  return FACE_CVPCB;
313 
314  case FRAME_GERBER:
315  return FACE_GERBVIEW;
316 
317  case FRAME_PL_EDITOR:
318  return FACE_PL_EDITOR;
319 
320  case FRAME_CALC:
321  return FACE_PCB_CALCULATOR;
322 
323  case FRAME_BM2CMP:
324  return FACE_BMP2CMP;
325 
326  default:
327  return FACE_T( -1 );
328  }
329 }
330 
331 
333 {
334  if( m_playerFrameName[aFrameType].IsEmpty() )
335  return NULL;
336 
337  return static_cast<KIWAY_PLAYER*>( wxWindow::FindWindowByName( m_playerFrameName[aFrameType] ) );
338 }
339 
340 
341 KIWAY_PLAYER* KIWAY::Player( FRAME_T aFrameType, bool doCreate, wxTopLevelWindow* aParent )
342 {
343  // Since this will be called from python, cannot assume that code will
344  // not pass a bad aFrameType.
345  if( (unsigned) aFrameType >= KIWAY_PLAYER_COUNT )
346  {
347  // @todo : throw an exception here for python's benefit, at least that
348  // way it gets some explanatory text.
349 
350  wxASSERT_MSG( 0, wxT( "caller has a bug, passed a bad aFrameType" ) );
351  return NULL;
352  }
353 
354  // return the previously opened window
355  KIWAY_PLAYER* frame = GetPlayerFrame( aFrameType );
356 
357  if( frame )
358  return frame;
359 
360  if( doCreate )
361  {
362  FACE_T face_type = KifaceType( aFrameType );
363  wxASSERT( face_type != FACE_T(-1) );
364 
365  KIFACE* kiface = KiFACE( face_type );
366  wxASSERT( kiface );
367 
368  if( kiface )
369  {
370  frame = (KIWAY_PLAYER*) kiface->CreateWindow(
371  aParent, // Parent window of frame in modal mode, NULL in non modal mode
372  aFrameType,
373  this,
374  m_ctl // questionable need, these same flags where passed
375  // to the KIFACE::OnKifaceStart()
376  );
377  wxASSERT( frame );
378 
379  m_playerFrameName[aFrameType] = frame->GetName();
380 
381  return frame;
382  }
383  }
384 
385  return NULL;
386 }
387 
388 
389 bool KIWAY::PlayerClose( FRAME_T aFrameType, bool doForce )
390 {
391  // Since this will be called from python, cannot assume that code will
392  // not pass a bad aFrameType.
393  if( (unsigned) aFrameType >= KIWAY_PLAYER_COUNT )
394  {
395  // @todo : throw an exception here for python's benefit, at least that
396  // way it gets some explanatory text.
397 
398  wxASSERT_MSG( 0, wxT( "caller has a bug, passed a bad aFrameType" ) );
399  return false;
400  }
401 
402  KIWAY_PLAYER* frame = GetPlayerFrame( aFrameType );
403 
404  if( frame == NULL ) // Already closed
405  return true;
406 
407  if( frame->Close( doForce ) )
408  return true;
409 
410  return false;
411 }
412 
413 
414 bool KIWAY::PlayersClose( bool doForce )
415 {
416  bool ret = true;
417 
418  for( unsigned i=0; i < KIWAY_PLAYER_COUNT; ++i )
419  {
420  ret = ret && PlayerClose( FRAME_T( i ), doForce );
421  }
422 
423  return ret;
424 }
425 
426 
427 void KIWAY::ExpressMail( FRAME_T aDestination, MAIL_T aCommand, std::string& aPayload, wxWindow* aSource )
428 {
429  KIWAY_EXPRESS mail( aDestination, aCommand, aPayload, aSource );
430 
431  ProcessEvent( mail );
432 }
433 
434 
435 void KIWAY::SetLanguage( int aLanguage )
436 {
437  Pgm().SetLanguageIdentifier( aLanguage );
438  Pgm().SetLanguage();
439 
440 #if 1
441  // This is a risky hack that goes away if we allow the language to be
442  // set only from the top most frame if !Kiface.IsSingle()
443 
444  // Only for the C++ project manager, and not for the python one and not for
445  // single_top do we look for the EDA_BASE_FRAME as the top level window.
446  // For single_top this is not needed because that window is registered in
447  // the array below.
449  {
450  // A dynamic_cast could be better, but creates link issues
451  // (some basic_frame functions not found) on some platforms,
452  // so a static_cast is used.
453  EDA_BASE_FRAME* top = static_cast<EDA_BASE_FRAME*>( m_top );
454 
455  if( top )
456  top->ShowChangedLanguage();
457  }
458 #endif
459 
460  for( unsigned i=0; i < KIWAY_PLAYER_COUNT; ++i )
461  {
462  KIWAY_PLAYER* frame = GetPlayerFrame( ( FRAME_T )i );
463 
464  if( frame )
465  {
466  frame->ShowChangedLanguage();
467  }
468  }
469 }
470 
471 void KIWAY::CommonSettingsChanged( bool aEnvVarsChanged )
472 {
473 #if 1
475  {
476  // A dynamic_cast could be better, but creates link issues
477  // (some basic_frame functions not found) on some platforms,
478  // so a static_cast is used.
479  EDA_BASE_FRAME* top = static_cast<EDA_BASE_FRAME*>( m_top );
480 
481  if( top )
482  top->CommonSettingsChanged( aEnvVarsChanged );
483  }
484 #endif
485 
486  for( unsigned i=0; i < KIWAY_PLAYER_COUNT; ++i )
487  {
488  KIWAY_PLAYER* frame = GetPlayerFrame( ( FRAME_T )i );
489 
490  if( frame )
491  frame->CommonSettingsChanged( aEnvVarsChanged );
492  }
493 }
494 
495 
496 bool KIWAY::ProcessEvent( wxEvent& aEvent )
497 {
498  KIWAY_EXPRESS* mail = dynamic_cast<KIWAY_EXPRESS*>( &aEvent );
499 
500  if( mail )
501  {
502  FRAME_T dest = mail->Dest();
503 
504  // see if recipient is alive
505  KIWAY_PLAYER* alive = Player( dest, false );
506 
507  if( alive )
508  {
509 #if 1
510  return alive->ProcessEvent( aEvent );
511 #else
512  alive->KiwayMailIn( *mail );
513  return true;
514 #endif
515  }
516  }
517 
518  return false;
519 }
520 
521 
523 {
525  {
526  // A dynamic_cast could be better, but creates link issues
527  // (some basic_frame functions not found) on some platforms,
528  // so a static_cast is used.
529  EDA_BASE_FRAME* top = static_cast<EDA_BASE_FRAME*>( m_top );
530 
531  if( top )
532  top->Close( false );
533  }
534 }
535 
536 
538 {
539  for( KIFACE* i : m_kiface )
540  {
541  if( i )
542  i->OnKifaceEnd();
543  }
544 }
#define KFCTL_CPP_PROJECT_SUITE
Am running under C++ project mgr, possibly with others.
Definition: kiway.h:160
VTBL_ENTRY bool PlayersClose(bool doForce)
Function PlayersClose calls the KIWAY_PLAYER::Close( bool force ) function on all the windows and if ...
Definition: kiway.cpp:414
Class KIWAY_PLAYER is a wxFrame capable of the OpenProjectFiles function, meaning it can load a porti...
Definition: kiway_player.h:59
Class KIWAY_EXPRESS carries a payload from one KIWAY_PLAYER to another within a PROJECT.
Definition: kiway_express.h:39
void OnKiCadExit()
Definition: kiway.cpp:522
Class PROJECT holds project specific data.
Definition: project.h:58
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
KIWAY_PLAYER * GetPlayerFrame(FRAME_T aFrameType)
Definition: kiway.cpp:332
VTBL_ENTRY void CommonSettingsChanged(bool aEnvVarsChanged)
Function CommonSettingsChanged Calls CommonSettingsChanged() on all KIWAY_PLAYERs.
Definition: kiway.cpp:471
Class PGM_BASE keeps program (whole process) data for KiCad programs.
Definition: pgm_base.h:156
#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 PROJECT & Prj() const
Function Prj returns the PROJECT associated with this KIWAY.
Definition: kiway.cpp:171
KIWAY(PGM_BASE *aProgram, int aCtlBits, wxFrame *aTop=NULL)
Definition: kiway.cpp:45
PGM_BASE * m_program
Definition: kiway.h:433
PGM_BASE & Pgm()
The global Program "get" accessor.
Definition: kicad.cpp:66
VTBL_ENTRY void SetLanguage(int aLanguage)
Function SetLanguage changes the language and then calls ShowChangedLanguage() on all KIWAY_PLAYERs.
Definition: kiway.cpp:435
void OnKiwayEnd()
Definition: kiway.cpp:537
#define KIFACE_INSTANCE_NAME_AND_VERSION
Definition: kiway.h:116
This file contains miscellaneous commonly used macros and functions.
MAIL_T
Enum MAIL_T is the set of mail types sendable via KIWAY::ExpressMail() and supplied as the aCommand p...
Definition: mail_type.h:37
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
VTBL_ENTRY void SetLanguageIdentifier(int menu_id)
Function SetLanguageIdentifier sets in .m_language_id member the wxWidgets language identifier Id fro...
Definition: pgm_base.cpp:725
VTBL_ENTRY bool PlayerClose(FRAME_T aFrameType, bool doForce)
Function PlayerClose calls the KIWAY_PLAYER::Close( bool force ) function on the window and if not ve...
Definition: kiway.cpp:389
bool ProcessEvent(wxEvent &aEvent) override
Definition: kiway.cpp:496
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:470
PROJECT m_project
Definition: kiway.h:446
int m_ctl
Definition: kiway.h:434
virtual void KiwayMailIn(KIWAY_EXPRESS &aEvent)
Function KiwayMailIn receives KIWAY_EXPRESS messages from other players.
pcbnew DSO
Definition: kiway.h:283
#define THROW_IO_ERROR(msg)
const wxString dso_search_path(FACE_T aFaceId)
Get the [path &] name of the DSO holding the requested FACE_T.
Definition: kiway.cpp:95
VTBL_ENTRY KIFACE * KiFACE(FACE_T aFaceId, bool doLoad=true)
Function KiFACE returns the KIFACE* given a FACE_T.
Definition: kiway.cpp:177
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
#define _(s)
VTBL_ENTRY bool SetLanguage(bool first_time=false)
Function SetLanguage sets the dictionary file name for internationalization.
Definition: pgm_base.cpp:633
FACE_T
Known KIFACE implementations.
Definition: kiway.h:280
constexpr std::size_t arrayDim(T const (&)[N]) noexcept
Definition: macros.h:108
eeschema DSO
Definition: kiway.h:282
virtual void CommonSettingsChanged(bool aEnvVarsChanged)
Notification event that some of the common (suite-wide) settings have changed.
VTBL_ENTRY void ExpressMail(FRAME_T aDestination, MAIL_T aCommand, std::string &aPayload, wxWindow *aSource=NULL)
Function ExpressMail send aPayload to aDestination from aSource.
Definition: kiway.cpp:427
FRAME_T Dest()
Function Dest returns the destination player id of the message.
Definition: kiway_express.h:46
see class PGM_BASE
const char * name
Definition: DXF_plotter.cpp:61
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
VTBL_ENTRY const wxString & GetExecutablePath() const
Definition: pgm_base.h:222
The base frame for deriving all KiCad main window classes.
size_t i
Definition: json11.cpp:649
Class KIFACE is used by a participant in the KIWAY alchemy.
Definition: kiway.h:151
static int m_kiface_version[KIWAY_FACE_COUNT]
Definition: kiway.h:431
wxArrayString m_playerFrameName
Definition: kiway.h:444
return & kiface
Definition: pcbnew.cpp:189
wxFrame * m_top
Definition: kiway.h:436
virtual void ShowChangedLanguage()
Redraw the menus and what not in current language.
bool ProcessEvent(wxEvent &aEvent) override
Override the default process event handler to implement the auto save feature.
int PGM_BASE * aProgram
Definition: pcbnew.cpp:187
static KIFACE * m_kiface[KIWAY_FACE_COUNT]
Definition: kiway.h:430
#define KFCTL_STANDALONE
Am running as a standalone Top.
Definition: kiway.h:159