File: single_top.cpp

package info (click to toggle)
kicad 9.0.3%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 770,320 kB
  • sloc: cpp: 961,692; ansic: 121,001; xml: 66,428; python: 18,387; sh: 1,010; awk: 301; asm: 292; makefile: 227; javascript: 167; perl: 10
file content (454 lines) | stat: -rw-r--r-- 13,420 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
/*
 * This program source code file is part of KiCad, a free EDA CAD application.
 *
 * Copyright (C) 2014 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, you may find one here:
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * or you may search the http://www.gnu.org website for the version 2 license,
 * or you may write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
 */


/*

    This is a program launcher for a single KIFACE DSO. It only mimics a KIWAY,
    not actually implements one, since only a single DSO is supported by it.

    It is compiled multiple times, once for each standalone program and as such
    gets different compiler command line supplied #defines from CMake.

*/


#include <typeinfo>
#include <wx/cmdline.h>
#include <wx/dialog.h>
#include <wx/filename.h>
#include <wx/stdpaths.h>
#include <wx/snglinst.h>
#include <wx/html/htmlwin.h>

#include <kiway.h>
#include <pgm_base.h>
#include <kiway_player.h>
#include <macros.h>
#include <confirm.h>
#include <settings/kicad_settings.h>
#include <settings/settings_manager.h>

#include <kiplatform/app.h>
#include <kiplatform/environment.h>

#include <git2.h>

#ifdef KICAD_USE_SENTRY
#include <sentry.h>
#endif

#ifdef KICAD_IPC_API
#include <api/api_server.h>
#endif

// Only a single KIWAY is supported in this single_top top level component,
// which is dedicated to loading only a single DSO.
KIWAY    Kiway( KFCTL_STANDALONE );


// implement a PGM_BASE and a wxApp side by side:

/**
 * Implement PGM_BASE with its own OnPgmInit() and OnPgmExit().
 */
static struct PGM_SINGLE_TOP : public PGM_BASE
{
    bool OnPgmInit();

    void OnPgmExit()
    {

        Kiway.OnKiwayEnd();

#ifdef KICAD_IPC_API
        m_api_server.reset();
#endif

        if( m_settings_manager && m_settings_manager->IsOK() )
        {
            SaveCommonSettings();
            m_settings_manager->Save();
        }

        // Destroy everything in PGM_BASE, especially wxSingleInstanceCheckerImpl
        // earlier than wxApp and earlier than static destruction would.
        PGM_BASE::Destroy();
        git_libgit2_shutdown();
    }

    void MacOpenFile( const wxString& aFileName )   override
    {
        wxFileName  filename( aFileName );

        if( filename.FileExists() )
        {
    #if 0
            // this pulls in EDA_DRAW_FRAME type info, which we don't want in
            // the single_top link image.
            KIWAY_PLAYER* frame = dynamic_cast<KIWAY_PLAYER*>( App().GetTopWindow() );
    #else
            KIWAY_PLAYER* frame = (KIWAY_PLAYER*) App().GetTopWindow();
    #endif
            if( frame )
            {
                if( wxWindow* blocking_win = frame->Kiway().GetBlockingDialog() )
                    blocking_win->Close( true );

                frame->OpenProjectFiles( std::vector<wxString>( 1, aFileName ) );
            }
        }
    }

} program;


// A module to allow Html module initialization/cleanup
// When a wxHtmlWindow is used *only* in a dll/so module, the Html text is displayed
// as plain text.
// This helper class is just used to force wxHtmlWinParser initialization
// see https://groups.google.com/forum/#!topic/wx-users/FF0zv5qGAT0
class HtmlModule: public wxModule
{
public:
    HtmlModule() { }
    virtual bool OnInit() override { AddDependency( CLASSINFO( wxHtmlWinParser ) ); return true; };
    virtual void OnExit() override {};

private:
    wxDECLARE_DYNAMIC_CLASS( HtmlModule );
};

wxIMPLEMENT_DYNAMIC_CLASS(HtmlModule, wxModule);


#ifdef NDEBUG
// Define a custom assertion handler
void CustomAssertHandler( const wxString& file,
                          int line,
                          const wxString& func,
                          const wxString& cond,
                          const wxString& msg )
{
    Pgm().HandleAssert( file, line, func, cond, msg );
}
#endif


/**
 * Implement a bare naked wxApp (so that we don't become dependent on
 * functionality in a wxApp derivative that we cannot deliver under wxPython).
 */
struct APP_SINGLE_TOP : public wxApp
{
    APP_SINGLE_TOP() : wxApp()
    {
        SetPgm( &program );

        // Init the environment each platform wants
        KIPLATFORM::ENV::Init();
    }


    bool OnInit() override
    {
#ifdef NDEBUG
        // These checks generate extra assert noise
        wxSizerFlags::DisableConsistencyChecks();
        wxDISABLE_DEBUG_SUPPORT();
        wxSetAssertHandler( CustomAssertHandler );
#endif

        // Perform platform-specific init tasks
        if( !KIPLATFORM::APP::Init() )
            return false;

#ifndef DEBUG
        // Enable logging traces to the console in release build.
        // This is usually disabled, but it can be useful for users to run to help
        // debug issues and other problems.
        if( wxGetEnv( wxS( "KICAD_ENABLE_WXTRACE" ), nullptr ) )
        {
            wxLog::EnableLogging( true );
            wxLog::SetLogLevel( wxLOG_Trace );
        }
#endif

        // Force wxHtmlWinParser initialization when a wxHtmlWindow is used only
        // in a shared library (.so or .dll file)
        // Otherwise the Html text is displayed as plain text.
        HtmlModule html_init;

        try
        {
            return program.OnPgmInit();
        }
        catch( ... )
        {
            Pgm().HandleException( std::current_exception() );
        }

        program.OnPgmExit();

        return false;
    }

    int  OnExit() override
    {
        program.OnPgmExit();
        return wxApp::OnExit();
    }

    int OnRun() override
    {
        int ret = -1;

        try
        {
            ret = wxApp::OnRun();
        }
        catch(...)
        {
            Pgm().HandleException( std::current_exception() );
        }

        return ret;
    }

    int FilterEvent( wxEvent& aEvent ) override
    {
        if( aEvent.GetEventType() == wxEVT_SHOW )
        {
            wxShowEvent& event = static_cast<wxShowEvent&>( aEvent );
            wxDialog*    dialog = dynamic_cast<wxDialog*>( event.GetEventObject() );

            std::vector<void*>& dlgs = Pgm().m_ModalDialogs;

            if( dialog )
            {
                if( event.IsShown() && dialog->IsModal() )
                {
                    dlgs.push_back( dialog );
                }
                // Under GTK, sometimes the modal flag is cleared before hiding
                else if( !event.IsShown() && !dlgs.empty()  )
                {
                    // If we close the expected dialog, remove it from our stack
                    if( dlgs.back() == dialog )
                        dlgs.pop_back();
                    // If an out-of-order, remove all dialogs added after the closed one
                    else if( auto it = std::find( dlgs.begin(), dlgs.end(), dialog );
                             it != dlgs.end() )
                        dlgs.erase( it, dlgs.end() );
                }
            }
        }

        return Event_Skip;
    }

#if defined( DEBUG )
    /**
     * Override main loop exception handling on debug builds.
     *
     * It can be painfully difficult to debug exceptions that happen in wxUpdateUIEvent
     * handlers.  The override provides a bit more useful information about the exception
     * and a breakpoint can be set to pin point the event where the exception was thrown.
     */
    virtual bool OnExceptionInMainLoop() override
    {
        try
        {
            throw;
        }
        catch( ... )
        {
            Pgm().HandleException( std::current_exception() );
        }

        return false;   // continue on. Return false to abort program
    }
#endif

#ifdef __WXMAC__

    /**
     * Specific to MacOSX (not used under Linux or Windows).
     *
     * MacOSX requires it for file association.
     *
     * @see http://wiki.wxwidgets.org/WxMac-specific_topics
     */
    void MacOpenFile( const wxString& aFileName ) override
    {
        Pgm().MacOpenFile( aFileName );
    }

#endif
};

IMPLEMENT_APP( APP_SINGLE_TOP )


bool PGM_SINGLE_TOP::OnPgmInit()
{
#if defined(DEBUG)
    wxString absoluteArgv0 = wxStandardPaths::Get().GetExecutablePath();

    if( !wxIsAbsolutePath( absoluteArgv0 ) )
    {
        wxLogError( wxT( "No meaningful argv[0]" ) );
        return false;
    }
#endif

    // Initialize the git library before trying to initialize individual programs
    git_libgit2_init();

    // Not all KiCad applications use the python stuff. skip python init
    // for these apps.
    bool skip_python_initialization = false;

#if defined( BITMAP_2_CMP ) || defined( PL_EDITOR ) || defined( GERBVIEW ) || \
    defined( PCB_CALCULATOR_BUILD )
    skip_python_initialization = true;
#endif

    if( !InitPgm( false, skip_python_initialization ) )
    {
        // Clean up
        OnPgmExit();
        return false;
    }

#if !defined(BUILD_KIWAY_DLL)

    // Only bitmap2component and pcb_calculator use this code currently, as they
    // are not split to use single_top as a link image separate from a *.kiface.
    // i.e. they are single part link images so don't need to load a *.kiface.

    // Get the getter, it is statically linked into this binary image.
    KIFACE_GETTER_FUNC* ki_getter = &KIFACE_GETTER;

    int  kiface_version;

    // Get the KIFACE.
    KIFACE* kiface = ki_getter( &kiface_version, KIFACE_VERSION, this );

    // Trick the KIWAY into thinking it loaded a KIFACE, by recording the KIFACE
    // in the KIWAY.  It needs to be there for KIWAY::OnKiwayEnd() anyways.
    Kiway.set_kiface( KIWAY::KifaceType( TOP_FRAME ), kiface );
#endif

    // Tell the settings manager about the current Kiway
    GetSettingsManager().SetKiway( &Kiway );

    GetSettingsManager().RegisterSettings( new KICAD_SETTINGS );

#ifdef KICAD_IPC_API
    // Create the API server thread once the app event loop exists
    m_api_server = std::make_unique<KICAD_API_SERVER>();
#endif

    // Use KIWAY to create a top window, which registers its existence also.
    // "TOP_FRAME" is a macro that is passed on compiler command line from CMake,
    // and is one of the types in FRAME_T.
    KIWAY_PLAYER* frame = Kiway.Player( TOP_FRAME, true );

    if( frame == nullptr )
    {
        // Clean up
        OnPgmExit();
        return false;
    }

    Kiway.SetTop( frame );

    App().SetTopWindow( frame );      // wxApp gets a face.
    App().SetAppDisplayName( frame->GetAboutTitle() );

    // Allocate a slice of time to show the frame and update wxWidgets widgets
    // (especially setting valid sizes) after creating frame and before calling
    // OpenProjectFiles() that can update/use some widgets.
    // The 2 calls to wxSafeYield are needed on wxGTK for best results.
    wxSafeYield();
    HideSplash();
    frame->Show();
    wxSafeYield();

    // Now after the frame processing, the rest of the positional args are files
    std::vector<wxString> fileArgs;


    static const wxCmdLineEntryDesc desc[] = {
        { wxCMD_LINE_PARAM, nullptr, nullptr, "File to load", wxCMD_LINE_VAL_STRING,
          wxCMD_LINE_PARAM_MULTIPLE | wxCMD_LINE_PARAM_OPTIONAL },
        { wxCMD_LINE_NONE, nullptr, nullptr, nullptr, wxCMD_LINE_VAL_NONE, 0 }
    };

    wxCmdLineParser parser( App().argc, App().argv );
    parser.SetDesc( desc );
    parser.Parse( false );

    if( parser.GetParamCount() )
    {
        /*
            gerbview handles multiple project data files, i.e. gerber files on
            cmd line. Others currently do not, they handle only one. For common
            code simplicity we simply pass all the arguments in however, each
            program module can do with them what they want, ignore, complain
            whatever.  We don't establish policy here, as this is a multi-purpose
            launcher.
        */

        for( size_t i = 0; i < parser.GetParamCount(); i++ )
            fileArgs.push_back( parser.GetParam( i ) );

        // special attention to a single argument: argv[1] (==argSet[0])
        if( fileArgs.size() == 1 )
        {
            wxFileName argv1( fileArgs[0] );

#if defined(PGM_DATA_FILE_EXT)
            // PGM_DATA_FILE_EXT, if present, may be different for each compile,
            // it may come from CMake on the compiler command line, but often does not.
            // This facility is mostly useful for those program footprints
            // supporting a single argv[1].
            if( !argv1.GetExt() )
                argv1.SetExt( wxT( PGM_DATA_FILE_EXT ) );
#endif
            argv1.MakeAbsolute();

            fileArgs[0] = argv1.GetFullPath();
        }

        frame->OpenProjectFiles( fileArgs );
    }

#ifdef KICAD_IPC_API
    m_api_server->SetReadyToReply();
#endif

    return true;
}