Change the way main editor frames are managed by Kicad: before this change, they had the Kicad manager frame as parent frame, and it creates a few issues:

- When the Kicad manager is iconized, all other child frames are iconized (normal wxWidgets behavior)
- For viewer frames in modal mode, there is a more annoying issue: they have the wxFLOAT_ON_PARENT frame style on unix, and wxSTAY_ON_TOP on Windows.
wxFLOAT_ON_PARENT frame style is incorrect (although on most WM it works) because the parent frame (Kicad manager Frame) is not the caller. It is usually a main editor frame.
It does not work on Windows (wx STAY_ON_TOP is used).
* Now each editor frame has a null parent.
Therefore iconizing the Kicad manager frame does not iconize other frames.
* Viewer frames have null parent in normal mode and the caller parent in modal mode (therefore wxFLOAT_ON_PARENT frame style is always and correctly used)
* References to opened/closed main frames are no more managed by the (complicated) kicad code. Instead of, a non critical and more easy to understand code just uses FindWindowByName to know if a main window exists or not.

These changes do not fix all issues about Kicad frames brought to the foreground or the background, but it fixes a few issues, and AFAIK do not add other issues.
This commit is contained in:
jean-pierre charras 2016-03-21 17:36:06 +01:00
parent 2d4845ddae
commit 99d18faca9
9 changed files with 94 additions and 74 deletions

View File

@ -48,10 +48,19 @@ KIWAY::KIWAY( PGM_BASE* aProgram, int aCtlBits, wxFrame* aTop ):
{ {
SetTop( aTop ); // hook player_destroy_handler() into aTop. SetTop( aTop ); // hook player_destroy_handler() into aTop.
memset( m_player, 0, sizeof( m_player ) );
// Prepare the room to store the frame names, once they will be created
// with FRAME_T type as index in this table.
// (note this is a list of frame names, but a non empty entry
// does not mean the frame still exists. It means only the frame was created
// at least once. It can be destroyed after. These entries are not cleared.
// the purpose is just to allow a call to wxWindow::FindWindowByName(), from
// a FRAME_T frame type
m_playerFrameName.Add( wxEmptyString, KIWAY_PLAYER_COUNT );
} }
#if 0
// Any event types derived from wxCommandEvt, like wxWindowDestroyEvent, are // Any event types derived from wxCommandEvt, like wxWindowDestroyEvent, are
// propogated upwards to parent windows if not handled below. Therefore the // propogated upwards to parent windows if not handled below. Therefore the
// m_top window should receive all wxWindowDestroyEvents originating from // m_top window should receive all wxWindowDestroyEvents originating from
@ -60,26 +69,14 @@ KIWAY::KIWAY( PGM_BASE* aProgram, int aCtlBits, wxFrame* aTop ):
void KIWAY::player_destroy_handler( wxWindowDestroyEvent& event ) void KIWAY::player_destroy_handler( wxWindowDestroyEvent& event )
{ {
wxWindow* w = event.GetWindow(); // Currently : do nothing
for( unsigned i=0; i < KIWAY_PLAYER_COUNT; ++i )
{
// if destroying one of our flock, then mark it as deceased.
if( (wxWindow*) m_player[i] == w )
{
DBG(printf( "%s: m_player[%u] destroyed: %s\n",
__func__, i, TO_UTF8( m_player[i]->GetName() ) );)
m_player[i] = 0;
}
}
event.Skip(); // skip to who, the wxApp? I'm the top window. event.Skip(); // skip to who, the wxApp? I'm the top window.
} }
#endif
void KIWAY::SetTop( wxFrame* aTop ) void KIWAY::SetTop( wxFrame* aTop )
{ {
#if 0
if( m_top ) if( m_top )
{ {
m_top->Disconnect( wxEVT_DESTROY, wxWindowDestroyEventHandler( KIWAY::player_destroy_handler ), NULL, this ); m_top->Disconnect( wxEVT_DESTROY, wxWindowDestroyEventHandler( KIWAY::player_destroy_handler ), NULL, this );
@ -89,6 +86,7 @@ void KIWAY::SetTop( wxFrame* aTop )
{ {
aTop->Connect( wxEVT_DESTROY, wxWindowDestroyEventHandler( KIWAY::player_destroy_handler ), NULL, this ); aTop->Connect( wxEVT_DESTROY, wxWindowDestroyEventHandler( KIWAY::player_destroy_handler ), NULL, this );
} }
#endif
m_top = aTop; m_top = aTop;
} }
@ -271,14 +269,15 @@ KIWAY::FACE_T KIWAY::KifaceType( FRAME_T aFrameType )
KIWAY_PLAYER* KIWAY::GetPlayerFrame( FRAME_T aFrameType ) KIWAY_PLAYER* KIWAY::GetPlayerFrame( FRAME_T aFrameType )
{ {
if( unsigned( aFrameType ) >= KIWAY_PLAYER_COUNT ) if( m_playerFrameName[aFrameType].IsEmpty() )
return NULL; return NULL;
return m_player[aFrameType]; return static_cast<KIWAY_PLAYER*>( wxWindow::FindWindowByName( m_playerFrameName[aFrameType] ) );
} }
KIWAY_PLAYER* KIWAY::Player( FRAME_T aFrameType, bool doCreate )
KIWAY_PLAYER* KIWAY::Player( FRAME_T aFrameType, bool doCreate, KIWAY_PLAYER* aParent )
{ {
// Since this will be called from python, cannot assume that code will // Since this will be called from python, cannot assume that code will
// not pass a bad aFrameType. // not pass a bad aFrameType.
@ -308,14 +307,16 @@ KIWAY_PLAYER* KIWAY::Player( FRAME_T aFrameType, bool doCreate )
if( kiface ) if( kiface )
{ {
frame = (KIWAY_PLAYER*) kiface->CreateWindow( frame = (KIWAY_PLAYER*) kiface->CreateWindow(
m_top, aParent, // Parent window of frame, NULL in non modal mode
aFrameType, aFrameType,
this, this,
m_ctl // questionable need, these same flags where passed to the KIFACE::OnKifaceStart() m_ctl // questionable need, these same flags where passed to the KIFACE::OnKifaceStart()
); );
wxASSERT( frame ); wxASSERT( frame );
return m_player[aFrameType] = frame; m_playerFrameName[aFrameType] = frame->GetName();
return frame;
} }
} }
@ -342,10 +343,7 @@ bool KIWAY::PlayerClose( FRAME_T aFrameType, bool doForce )
return true; return true;
if( frame->Close( doForce ) ) if( frame->Close( doForce ) )
{
m_player[aFrameType] = 0;
return true; return true;
}
return false; return false;
} }

View File

@ -532,7 +532,7 @@ void DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::showButtonHandler( wxCommandEvent& even
// pick a footprint using the footprint picker. // pick a footprint using the footprint picker.
wxString fpid; wxString fpid;
KIWAY_PLAYER* frame = Kiway().Player( FRAME_PCB_MODULE_VIEWER_MODAL, true ); KIWAY_PLAYER* frame = Kiway().Player( FRAME_PCB_MODULE_VIEWER_MODAL, true, m_parent );
if( frame->ShowModal( &fpid, this ) ) if( frame->ShowModal( &fpid, this ) )
{ {

View File

@ -62,7 +62,7 @@ wxString SCH_BASE_FRAME::SelectComponentFromLibBrowser( const SCHLIB_FILTER* aFi
if( viewlibFrame ) if( viewlibFrame )
viewlibFrame->Destroy(); viewlibFrame->Destroy();
viewlibFrame = (LIB_VIEW_FRAME*) Kiway().Player( FRAME_SCH_VIEWER_MODAL, true ); viewlibFrame = (LIB_VIEW_FRAME*) Kiway().Player( FRAME_SCH_VIEWER_MODAL, true, this );
if( aFilter ) if( aFilter )
viewlibFrame->SetFilter( aFilter ); viewlibFrame->SetFilter( aFilter );

View File

@ -77,20 +77,22 @@ END_EVENT_TABLE()
/* Note: /* Note:
* LIB_VIEW_FRAME can be build in "modal mode", or as a usual frame. * LIB_VIEW_FRAME can be created in "modal mode", or as a usual frame.
* In modal mode: * In modal mode:
* a tool to export the selected symbol is shown in the toolbar * a tool to export the selected symbol is shown in the toolbar
* the style is wxSTAY_ON_TOP on Windows and wxFRAME_FLOAT_ON_PARENT on unix * the style is wxFRAME_FLOAT_ON_PARENT
* reason: * Note:
* the parent is usually the kicad window manager (not easy to change) * On windows, when the frame with type wxFRAME_FLOAT_ON_PARENT is displayed
* On windows, when the frame with stype wxFRAME_FLOAT_ON_PARENT is displayed * its parent frame is sometimes brought to the foreground when closing the
* its parent frame is brought to the foreground, on the top of the calling frame. * LIB_VIEW_FRAME frame.
* and stays displayed when closing the LIB_VIEW_FRAME frame. * If it still happens, it could be better to use wxSTAY_ON_TOP
* this issue does not happen on unix. * instead of wxFRAME_FLOAT_ON_PARENT
*
* So we use wxSTAY_ON_TOP on Windows, and wxFRAME_FLOAT_ON_PARENT on unix
* to simulate a dialog called by ShowModal.
*/ */
#ifdef __WINDOWS__
#define MODAL_MODE_EXTRASTYLE wxFRAME_FLOAT_ON_PARENT // could be wxSTAY_ON_TOP if issues
#else
#define MODAL_MODE_EXTRASTYLE wxFRAME_FLOAT_ON_PARENT
#endif
#define LIB_VIEW_FRAME_NAME wxT( "ViewlibFrame" ) #define LIB_VIEW_FRAME_NAME wxT( "ViewlibFrame" )
#define LIB_VIEW_FRAME_NAME_MODAL wxT( "ViewlibFrameModal" ) #define LIB_VIEW_FRAME_NAME_MODAL wxT( "ViewlibFrameModal" )
@ -99,18 +101,15 @@ LIB_VIEW_FRAME::LIB_VIEW_FRAME( KIWAY* aKiway, wxWindow* aParent, FRAME_T aFrame
PART_LIB* aLibrary ) : PART_LIB* aLibrary ) :
SCH_BASE_FRAME( aKiway, aParent, aFrameType, _( "Library Browser" ), SCH_BASE_FRAME( aKiway, aParent, aFrameType, _( "Library Browser" ),
wxDefaultPosition, wxDefaultSize, wxDefaultPosition, wxDefaultSize,
aFrameType==FRAME_SCH_VIEWER_MODAL ? aFrameType == FRAME_SCH_VIEWER_MODAL ?
#ifdef __WINDOWS__ aParent ? KICAD_DEFAULT_DRAWFRAME_STYLE | MODAL_MODE_EXTRASTYLE
KICAD_DEFAULT_DRAWFRAME_STYLE | wxSTAY_ON_TOP
#else
aParent ? KICAD_DEFAULT_DRAWFRAME_STYLE | wxFRAME_FLOAT_ON_PARENT
: KICAD_DEFAULT_DRAWFRAME_STYLE | wxSTAY_ON_TOP : KICAD_DEFAULT_DRAWFRAME_STYLE | wxSTAY_ON_TOP
#endif
: KICAD_DEFAULT_DRAWFRAME_STYLE, : KICAD_DEFAULT_DRAWFRAME_STYLE,
aFrameType == FRAME_SCH_VIEWER_MODAL ? aFrameType == FRAME_SCH_VIEWER_MODAL ?
LIB_VIEW_FRAME_NAME_MODAL : LIB_VIEW_FRAME_NAME ) LIB_VIEW_FRAME_NAME_MODAL : LIB_VIEW_FRAME_NAME )
{ {
wxASSERT( aFrameType == FRAME_SCH_VIEWER || aFrameType == FRAME_SCH_VIEWER_MODAL ); wxASSERT( aFrameType == FRAME_SCH_VIEWER ||
aFrameType == FRAME_SCH_VIEWER_MODAL );
if( aFrameType == FRAME_SCH_VIEWER_MODAL ) if( aFrameType == FRAME_SCH_VIEWER_MODAL )
SetModal( true ); SetModal( true );

View File

@ -298,11 +298,13 @@ public:
* @param aFrameType is from enum #FRAME_T. * @param aFrameType is from enum #FRAME_T.
* @param doCreate when true asks that the player be created if it is not * @param doCreate when true asks that the player be created if it is not
* already created, false means do not create and maybe return NULL. * already created, false means do not create and maybe return NULL.
* @param aParent is a parent for modal KIWAY_PLAYER frames, otherwise NULL
* used only when doCreate = true
* *
* @return KIWAY_PLAYER* - a valid opened KIWAY_PLAYER or NULL if there * @return KIWAY_PLAYER* - a valid opened KIWAY_PLAYER or NULL if there
* is something wrong or doCreate was false and the player has yet to be created. * is something wrong or doCreate was false and the player has yet to be created.
*/ */
VTBL_ENTRY KIWAY_PLAYER* Player( FRAME_T aFrameType, bool doCreate = true ); VTBL_ENTRY KIWAY_PLAYER* Player( FRAME_T aFrameType, bool doCreate = true, KIWAY_PLAYER* aParent = NULL );
/** /**
* Function PlayerClose * Function PlayerClose
@ -369,8 +371,10 @@ private:
/// Get the full path & name of the DSO holding the requested FACE_T. /// Get the full path & name of the DSO holding the requested FACE_T.
static const wxString dso_full_path( FACE_T aFaceId ); static const wxString dso_full_path( FACE_T aFaceId );
#if 0
/// hooked into m_top in SetTop(), marks child frame as closed. /// hooked into m_top in SetTop(), marks child frame as closed.
void player_destroy_handler( wxWindowDestroyEvent& event ); void player_destroy_handler( wxWindowDestroyEvent& event );
#endif
bool set_kiface( FACE_T aFaceType, KIFACE* aKiface ) bool set_kiface( FACE_T aFaceType, KIFACE* aKiface )
{ {
@ -393,10 +397,17 @@ private:
PGM_BASE* m_program; PGM_BASE* m_program;
int m_ctl; int m_ctl;
wxFrame* m_top; // Usually m_top is the Project manager wxFrame* m_top; // Usually m_top is the Project manager
KIWAY_PLAYER* m_player[KIWAY_PLAYER_COUNT]; // from frame_type.h // a string array ( size KIWAY_PLAYER_COUNT ) to Store the frame name
// of PLAYER frames which were run.
// A non empty name means only a PLAYER was run at least one time.
// It can be closed. Call :
// wxWindow::FindWindowByName( m_playerFrameName[aFrameType] )
// to know if still exists (or GetPlayerFrame( FRAME_T aFrameType )
wxArrayString m_playerFrameName;
PROJECT m_project; // do not assume this is here, use Prj(). PROJECT m_project; // do not assume this is here, use Prj().
}; };

View File

@ -88,16 +88,26 @@ int FOOTPRINT_WIZARD_FRAME::m_columnPrmUnit = 2;
#define FOOTPRINT_WIZARD_FRAME_NAME wxT( "FootprintWizard" ) #define FOOTPRINT_WIZARD_FRAME_NAME wxT( "FootprintWizard" )
/* Note: our FOOTPRINT_WIZARD_FRAME is always modal.
* Note:
* On windows, when the frame with type wxFRAME_FLOAT_ON_PARENT is displayed
* its parent frame is sometimes brought to the foreground when closing the
* LIB_VIEW_FRAME frame.
* If it still happens, it could be better to use wxSTAY_ON_TOP
* instead of wxFRAME_FLOAT_ON_PARENT
*/
#ifdef __WINDOWS__
#define MODAL_MODE_EXTRASTYLE wxFRAME_FLOAT_ON_PARENT // could be wxSTAY_ON_TOP if issues
#else
#define MODAL_MODE_EXTRASTYLE wxFRAME_FLOAT_ON_PARENT
#endif
FOOTPRINT_WIZARD_FRAME::FOOTPRINT_WIZARD_FRAME( KIWAY* aKiway, FOOTPRINT_WIZARD_FRAME::FOOTPRINT_WIZARD_FRAME( KIWAY* aKiway,
wxWindow* aParent, FRAME_T aFrameType ) : wxWindow* aParent, FRAME_T aFrameType ) :
PCB_BASE_FRAME( aKiway, aParent, aFrameType, _( "Footprint Wizard" ), PCB_BASE_FRAME( aKiway, aParent, aFrameType, _( "Footprint Wizard" ),
wxDefaultPosition, wxDefaultSize, wxDefaultPosition, wxDefaultSize,
#ifdef __WINDOWS__ aParent ? KICAD_DEFAULT_DRAWFRAME_STYLE | MODAL_MODE_EXTRASTYLE
KICAD_DEFAULT_DRAWFRAME_STYLE | wxSTAY_ON_TOP,
#else
aParent ? KICAD_DEFAULT_DRAWFRAME_STYLE | wxFRAME_FLOAT_ON_PARENT
: KICAD_DEFAULT_DRAWFRAME_STYLE | wxSTAY_ON_TOP, : KICAD_DEFAULT_DRAWFRAME_STYLE | wxSTAY_ON_TOP,
#endif
FOOTPRINT_WIZARD_FRAME_NAME ) FOOTPRINT_WIZARD_FRAME_NAME )
{ {
wxASSERT( aFrameType == FRAME_PCB_FOOTPRINT_WIZARD_MODAL ); wxASSERT( aFrameType == FRAME_PCB_FOOTPRINT_WIZARD_MODAL );

View File

@ -136,17 +136,17 @@ wxString PCB_BASE_FRAME::SelectFootprintFromLibBrowser()
{ {
// Close the current non-modal Lib browser if opened, and open a new one, in "modal" mode: // Close the current non-modal Lib browser if opened, and open a new one, in "modal" mode:
FOOTPRINT_VIEWER_FRAME* viewer; FOOTPRINT_VIEWER_FRAME* viewer;
viewer = (FOOTPRINT_VIEWER_FRAME*) Kiway().Player( FRAME_PCB_MODULE_VIEWER, false ); viewer = (FOOTPRINT_VIEWER_FRAME*) Kiway().Player( FRAME_PCB_MODULE_VIEWER, false );
if( viewer ) if( viewer )
viewer->Destroy(); viewer->Destroy();
SetFocus();
// Creates the modal Lib browser: // Creates the modal Lib browser:
viewer = (FOOTPRINT_VIEWER_FRAME*) Kiway().Player( FRAME_PCB_MODULE_VIEWER_MODAL, true ); viewer = (FOOTPRINT_VIEWER_FRAME*) Kiway().Player( FRAME_PCB_MODULE_VIEWER_MODAL, true, this );
wxString fpid; wxString fpid;
int ret = viewer->ShowModal( &fpid, this ); int ret = viewer->ShowModal( &fpid, this );
(void) ret; // make static analyser quiet (void) ret; // make static analyser quiet

View File

@ -344,7 +344,7 @@ void FOOTPRINT_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event )
} }
FOOTPRINT_WIZARD_FRAME* wizard = (FOOTPRINT_WIZARD_FRAME*) Kiway().Player( FOOTPRINT_WIZARD_FRAME* wizard = (FOOTPRINT_WIZARD_FRAME*) Kiway().Player(
FRAME_PCB_FOOTPRINT_WIZARD_MODAL, true ); FRAME_PCB_FOOTPRINT_WIZARD_MODAL, true, this );
if( wizard->ShowModal( NULL, this ) ) if( wizard->ShowModal( NULL, this ) )
{ {

View File

@ -100,18 +100,19 @@ END_EVENT_TABLE()
* FOOTPRINT_VIEWER_FRAME can be created in "modal mode", or as a usual frame. * FOOTPRINT_VIEWER_FRAME can be created in "modal mode", or as a usual frame.
* In modal mode: * In modal mode:
* a tool to export the selected footprint is shown in the toolbar * a tool to export the selected footprint is shown in the toolbar
* the style is wxSTAY_ON_TOP on Windows and wxFRAME_FLOAT_ON_PARENT on unix * the style is wxFRAME_FLOAT_ON_PARENT
* Reason: * Note:
* the parent is usually the kicad window manager (not easy to change) * On windows, when the frame with type wxFRAME_FLOAT_ON_PARENT is displayed
* On windows, when the frame with stype wxFRAME_FLOAT_ON_PARENT is displayed * its parent frame is sometimes brought to the foreground when closing the
* its parent frame is brought to the foreground, on the top of the calling frame. * LIB_VIEW_FRAME frame.
* and stays displayed when closing the FOOTPRINT_VIEWER_FRAME frame. * If it still happens, it could be better to use wxSTAY_ON_TOP
* this issue does not happen on unix * instead of wxFRAME_FLOAT_ON_PARENT
*
* So we use wxSTAY_ON_TOP on Windows, and wxFRAME_FLOAT_ON_PARENT on unix
* to force FOOTPRINT_VIEWER_FRAME to stay on parent when it is Modal.
*/ */
#ifdef __WINDOWS__
#define MODAL_MODE_EXTRASTYLE wxFRAME_FLOAT_ON_PARENT // could be wxSTAY_ON_TOP if issues
#else
#define MODAL_MODE_EXTRASTYLE wxFRAME_FLOAT_ON_PARENT
#endif
#define FOOTPRINT_VIEWER_FRAME_NAME wxT( "ModViewFrame" ) #define FOOTPRINT_VIEWER_FRAME_NAME wxT( "ModViewFrame" )
#define FOOTPRINT_VIEWER_FRAME_NAME_MODAL wxT( "ModViewFrameModal" ) #define FOOTPRINT_VIEWER_FRAME_NAME_MODAL wxT( "ModViewFrameModal" )
@ -121,20 +122,16 @@ FOOTPRINT_VIEWER_FRAME::FOOTPRINT_VIEWER_FRAME( KIWAY* aKiway, wxWindow* aParent
PCB_BASE_FRAME( aKiway, aParent, aFrameType, _( "Footprint Library Browser" ), PCB_BASE_FRAME( aKiway, aParent, aFrameType, _( "Footprint Library Browser" ),
wxDefaultPosition, wxDefaultSize, wxDefaultPosition, wxDefaultSize,
aFrameType == FRAME_PCB_MODULE_VIEWER_MODAL ? aFrameType == FRAME_PCB_MODULE_VIEWER_MODAL ?
#ifdef __WINDOWS__
KICAD_DEFAULT_DRAWFRAME_STYLE | wxSTAY_ON_TOP
#else
aParent ? aParent ?
KICAD_DEFAULT_DRAWFRAME_STYLE | wxFRAME_FLOAT_ON_PARENT KICAD_DEFAULT_DRAWFRAME_STYLE | MODAL_MODE_EXTRASTYLE
: KICAD_DEFAULT_DRAWFRAME_STYLE | wxSTAY_ON_TOP : KICAD_DEFAULT_DRAWFRAME_STYLE | wxSTAY_ON_TOP
#endif
: KICAD_DEFAULT_DRAWFRAME_STYLE, : KICAD_DEFAULT_DRAWFRAME_STYLE,
aFrameType == FRAME_PCB_MODULE_VIEWER_MODAL ? aFrameType == FRAME_PCB_MODULE_VIEWER_MODAL ?
FOOTPRINT_VIEWER_FRAME_NAME_MODAL FOOTPRINT_VIEWER_FRAME_NAME_MODAL
: FOOTPRINT_VIEWER_FRAME_NAME ) : FOOTPRINT_VIEWER_FRAME_NAME )
{ {
wxASSERT( aFrameType==FRAME_PCB_MODULE_VIEWER || wxASSERT( aFrameType == FRAME_PCB_MODULE_VIEWER_MODAL ||
aFrameType==FRAME_PCB_MODULE_VIEWER_MODAL ); aFrameType == FRAME_PCB_MODULE_VIEWER );
if( aFrameType == FRAME_PCB_MODULE_VIEWER_MODAL ) if( aFrameType == FRAME_PCB_MODULE_VIEWER_MODAL )
SetModal( true ); SetModal( true );
@ -305,6 +302,11 @@ void FOOTPRINT_VIEWER_FRAME::OnCloseWindow( wxCloseEvent& Event )
{ {
DBG(printf( "%s:\n", __func__ );) DBG(printf( "%s:\n", __func__ );)
// A workaround to avoid flicker, in modal mode when modview frame is destroyed,
// when the aui toolbar is not docked (i.e. shown in a miniframe)
// (usefull on windows only)
m_mainToolBar->SetFocus();
if( IsGalCanvasActive() ) if( IsGalCanvasActive() )
GetGalCanvas()->StopDrawing(); GetGalCanvas()->StopDrawing();