Add shutdown blocking on Windows for pcbnew, eeschema and pleditor

ADDED: Block shutdown/logoff on Windows when contents have been modified
This commit is contained in:
Mark Roszko 2019-12-19 14:11:11 +00:00 committed by Ian McInerney
parent 3ca231aa78
commit 686b768a3d
9 changed files with 151 additions and 12 deletions

View File

@ -159,6 +159,48 @@ void EDA_BASE_FRAME::windowClosing( wxCloseEvent& event )
EDA_BASE_FRAME::~EDA_BASE_FRAME()
{
delete m_autoSaveTimer;
if( SupportsShutdownBlockReason() )
{
RemoveShutdownBlockReason();
}
}
bool EDA_BASE_FRAME::SupportsShutdownBlockReason()
{
#if defined( _WIN32 )
return true;
#else
return false;
#endif
}
void EDA_BASE_FRAME::RemoveShutdownBlockReason()
{
#if defined( _WIN32 )
// Windows: Destroys any block reason that may have existed
ShutdownBlockReasonDestroy( GetHandle() );
#endif
}
void EDA_BASE_FRAME::SetShutdownBlockReason( const wxString& aReason )
{
#if defined( _WIN32 )
// Windows: sets up the pretty message on the shutdown page on why it's being "blocked"
// This is used in conjunction with handling WM_QUERYENDSESSION (wxCloseEvent)
// ShutdownBlockReasonCreate does not block by itself
ShutdownBlockReasonDestroy( GetHandle() ); // Destroys any existing or nonexisting reason
if( !ShutdownBlockReasonCreate( GetHandle(), aReason.wc_str() ) )
{
// Nothing bad happens if this fails, at worst it uses a generic application is preventing shutdown message
wxLogDebug( wxT( "ShutdownBlockReasonCreate failed to set reason: %s" ), aReason );
}
#endif
}

View File

@ -178,6 +178,8 @@ CVPCB_MAINFRAME::CVPCB_MAINFRAME( KIWAY* aKiway, wxWindow* aParent ) :
// Ensure the toolbars are sync'd properly so the filtering options display correct
SyncToolbars();
SetShutdownBlockReason( _( "Symbol to footprint changes are unsaved" ) );
}
@ -302,15 +304,22 @@ void CVPCB_MAINFRAME::setupEventHandlers()
}
void CVPCB_MAINFRAME::OnCloseWindow( wxCloseEvent& Event )
void CVPCB_MAINFRAME::OnCloseWindow( wxCloseEvent& aEvent )
{
if( m_modified )
{
// Shutdown blocks must be determined and vetoed as early as possible
if( SupportsShutdownBlockReason() && aEvent.GetId() == wxEVT_QUERY_END_SESSION )
{
aEvent.Veto();
return;
}
if( !HandleUnsavedChanges( this, _( "Symbol to Footprint links have been modified. "
"Save changes?" ),
[&]()->bool { return SaveFootprintAssociation( false ); } ) )
{
Event.Veto();
aEvent.Veto();
return;
}
}
@ -326,7 +335,7 @@ void CVPCB_MAINFRAME::OnCloseWindow( wxCloseEvent& Event )
// Skip the close event. Looks like needed to have the close event sent to the
// root class EDA_BASE_FRAME, and save config
Event.Skip();
aEvent.Skip();
}

View File

@ -271,6 +271,8 @@ bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
Prj().SetElem( PROJECT::ELEM_SYMBOL_LIB_TABLE, NULL );
Prj().SchSymbolLibTable();
SetShutdownBlockReason( _( "Schematic file changes are unsaved" ) );
if( is_new )
{
// mark new, unsaved file as modified.

View File

@ -189,6 +189,8 @@ LIB_EDIT_FRAME::LIB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
GetCanvas()->GetView()->SetBoundary( bbox );
m_toolManager->RunAction( ACTIONS::zoomFitScreen, true );
SetShutdownBlockReason( _( "Library changes are unsaved" ) );
}
@ -232,12 +234,25 @@ void LIB_EDIT_FRAME::setupTools()
}
void LIB_EDIT_FRAME::OnCloseWindow( wxCloseEvent& Event )
void LIB_EDIT_FRAME::OnCloseWindow( wxCloseEvent& aEvent )
{
// Shutdown blocks must be determined and vetoed as early as possible
if( SupportsShutdownBlockReason() && aEvent.GetId() == wxEVT_QUERY_END_SESSION )
{
for( const auto& libNickname : m_libMgr->GetLibraryNames() )
{
if( m_libMgr->IsLibraryModified( libNickname ) )
{
aEvent.Veto();
return;
}
}
}
if( saveAllLibraries( true ) )
Destroy();
else
Event.Veto();
aEvent.Veto();
}

View File

@ -301,6 +301,9 @@ SCH_EDIT_FRAME::SCH_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ):
DefaultExecFlags();
UpdateTitle();
// Default shutdown reason until a file is loaded
SetShutdownBlockReason( _( "New schematic file is unsaved" ) );
}
@ -497,6 +500,16 @@ void SCH_EDIT_FRAME::SaveUndoItemInUndoList( SCH_ITEM* aItem, bool aAppend )
void SCH_EDIT_FRAME::OnCloseWindow( wxCloseEvent& aEvent )
{
SCH_SHEET_LIST sheetList( g_RootSheet );
// Shutdown blocks must be determined and vetoed as early as possible
if( SupportsShutdownBlockReason() && aEvent.GetId() == wxEVT_QUERY_END_SESSION
&& sheetList.IsModified() )
{
aEvent.Veto();
return;
}
if( Kiface().IsSingle() )
{
LIB_EDIT_FRAME* libeditFrame = (LIB_EDIT_FRAME*) Kiway().Player( FRAME_SCH_LIB_EDITOR, false );
@ -518,7 +531,6 @@ void SCH_EDIT_FRAME::OnCloseWindow( wxCloseEvent& aEvent )
if( simFrame && !simFrame->Close() ) // Can close the simulator?
return;
SCH_SHEET_LIST sheetList( g_RootSheet );
if( sheetList.IsModified() )
{

View File

@ -466,6 +466,24 @@ public:
virtual void RefreshCanvas() { };
const wxString& GetAboutTitle() const { return m_AboutTitle; }
/**
* Sets the block reason why the window/application is preventing OS shutdown.
* This should be set far ahead of any close event.
*
* This is mainly intended for Windows platforms where this is a native feature.
*/
void SetShutdownBlockReason( const wxString& reason );
/**
* Removes any shutdown block reason set
*/
void RemoveShutdownBlockReason();
/**
* Whether or not the window supports setting a shutdown block reason
*/
bool SupportsShutdownBlockReason();
};

View File

@ -264,6 +264,14 @@ void PL_EDITOR_FRAME::OnExit( wxCommandEvent& aEvent )
void PL_EDITOR_FRAME::OnCloseWindow( wxCloseEvent& aEvent )
{
// Shutdown blocks must be determined and vetoed as early as possible
if( SupportsShutdownBlockReason() && aEvent.GetId() == wxEVT_QUERY_END_SESSION
&& GetScreen()->IsModify() )
{
aEvent.Veto();
return;
}
if( GetScreen()->IsModify() )
{
wxFileName filename = GetCurrFileName();
@ -764,6 +772,16 @@ void PL_EDITOR_FRAME::OnNewPageLayout()
UpdateTitleAndInfo();
m_toolManager->RunAction( ACTIONS::zoomFitScreen, true );
if( GetCurrFileName().IsEmpty() )
{
// Default shutdown reason until a file is loaded
SetShutdownBlockReason( _( "New page layout file is unsaved" ) );
}
else
{
SetShutdownBlockReason( _( "Page layout changes are unsaved" ) );
}
}

View File

@ -223,6 +223,9 @@ FOOTPRINT_EDIT_FRAME::FOOTPRINT_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent,
updateTitle();
InitExitKey();
// Default shutdown reason until a file is loaded
SetShutdownBlockReason( _( "Footprint changes are unsaved" ) );
Raise(); // On some window managers, this is needed
Show( true );
}
@ -444,17 +447,24 @@ const BOX2I FOOTPRINT_EDIT_FRAME::GetDocumentExtents() const
}
void FOOTPRINT_EDIT_FRAME::OnCloseWindow( wxCloseEvent& Event )
void FOOTPRINT_EDIT_FRAME::OnCloseWindow( wxCloseEvent& aEvent )
{
if( GetScreen()->IsModify() && GetBoard()->GetFirstModule() )
{
// Shutdown blocks must be determined and vetoed as early as possible
if( SupportsShutdownBlockReason() && aEvent.GetId() == wxEVT_QUERY_END_SESSION )
{
aEvent.Veto();
return;
}
wxString footprintName = GetBoard()->GetFirstModule()->GetFPID().GetLibItemName();
wxString msg = _( "Save changes to \"%s\" before closing?" );
if( !HandleUnsavedChanges( this, wxString::Format( msg, footprintName ),
[&]() -> bool { return SaveFootprint( GetBoard()->GetFirstModule() ); } ) )
{
Event.Veto();
aEvent.Veto();
return;
}
}
@ -470,7 +480,7 @@ void FOOTPRINT_EDIT_FRAME::OnCloseWindow( wxCloseEvent& Event )
Clear_Pcb( false );
// Close the editor
Event.Skip();
aEvent.Skip();
}

View File

@ -310,6 +310,9 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
GetCanvas()->GetView()->SetScale( GetZoomLevelCoeff() / GetScreen()->GetZoom() );
ActivateGalCanvas();
// Default shutdown reason until a file is loaded
SetShutdownBlockReason( _( "New PCB file is unsaved" ) );
// disable Export STEP item if kicad2step does not exist
wxString strK2S = Pgm().GetExecutablePath();
@ -464,8 +467,16 @@ void PCB_EDIT_FRAME::OnQuit( wxCommandEvent& event )
}
void PCB_EDIT_FRAME::OnCloseWindow( wxCloseEvent& Event )
void PCB_EDIT_FRAME::OnCloseWindow( wxCloseEvent& aEvent )
{
// Shutdown blocks must be determined and vetoed as early as possible
if( SupportsShutdownBlockReason() && aEvent.GetId() == wxEVT_QUERY_END_SESSION
&& GetScreen()->IsModify() && !GetBoard()->IsEmpty() )
{
aEvent.Veto();
return;
}
// First close the DRC dialog.
// For some reason, if the board editor frame is destroyed when the DRC
// dialog currently open, Pcbnew crashes, At least on Windows.
@ -483,7 +494,7 @@ void PCB_EDIT_FRAME::OnCloseWindow( wxCloseEvent& Event )
if( !HandleUnsavedChanges( this, wxString::Format( msg, fileName.GetFullName() ),
[&]()->bool { return Files_io_from_id( ID_SAVE_BOARD ); } ) )
{
Event.Veto();
aEvent.Veto();
return;
}
}
@ -538,7 +549,7 @@ void PCB_EDIT_FRAME::OnCloseWindow( wxCloseEvent& Event )
Show( false );
// Close frame:
Event.Skip();
aEvent.Skip();
}
@ -672,6 +683,8 @@ void PCB_EDIT_FRAME::onBoardLoaded()
SetMsgPanel( GetBoard() );
SetStatusText( wxEmptyString );
SetShutdownBlockReason( _( "PCB file changes are unsaved" ) );
}