KiCad PCB EDA Suite
Loading...
Searching...
No Matches
kiway_player.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 <[email protected]>
5 * Copyright The KiCad Developers, see AUTHORS.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#include <kiway_player.h>
27#include <kiway_mail.h>
28#include <kiway.h>
29#include <id.h>
30#include <macros.h>
31#include <typeinfo>
32#include <wx/utils.h>
33#include <wx/evtloop.h>
34#include <wx/socket.h>
35#include <core/raii.h>
36#include <wx/log.h>
37
38
39static const wxString HOSTNAME( wxT( "localhost" ) );
40
41// buffer for read and write data in socket connections
42#define IPC_BUF_SIZE 4096
44
45BEGIN_EVENT_TABLE( KIWAY_PLAYER, EDA_BASE_FRAME )
47END_EVENT_TABLE()
48
49
50KIWAY_PLAYER::KIWAY_PLAYER( KIWAY* aKiway, wxWindow* aParent, FRAME_T aFrameType,
51 const wxString& aTitle, const wxPoint& aPos, const wxSize& aSize,
52 long aStyle, const wxString& aFrameName,
53 const EDA_IU_SCALE& aIuScale ) :
54 EDA_BASE_FRAME( aParent, aFrameType, aTitle, aPos, aSize, aStyle, aFrameName, aKiway,
55 aIuScale ),
56 m_modal( false ),
57 m_modal_loop( nullptr ),
58 m_modal_resultant_parent( nullptr ),
59 m_modal_ret_val( false ),
60 m_socketServer( nullptr )
61{
62}
63
64
66{
67 // socket server must be destructed before we complete
68 // destructing the frame or else we could crash
69 // as the socket server holds a reference to this frame
70 if( m_socketServer )
71 {
72 // ensure any event handling stops
73 m_socketServer->Notify( false );
74
75 delete m_socketServer;
76 m_socketServer = nullptr;
77 }
78
79 // remove active sockets as well
80 for( wxSocketBase* socket : m_sockets )
81 {
82 if( !socket )
83 continue;
84
85 // ensure any event handling stops
86 socket->Notify( false );
87
88 delete socket;
89 }
90
91 m_sockets.clear();
92}
93
94
96{
97 // override this in derived classes.
98}
99
100
101bool KIWAY_PLAYER::ShowModal( wxString* aResult, wxWindow* aResultantFocusWindow )
102{
103 wxASSERT_MSG( IsModal(), wxT( "ShowModal() shouldn't be called on non-modal frame" ) );
104
105 /*
106 This function has a nice interface but a necessarily unsightly implementation.
107 Now the implementation is encapsulated, localizing future changes.
108
109 It works in tandem with DismissModal(). But only ShowModal() is in the
110 vtable and therefore cross-module capable.
111 */
112
113 NULLER raii_nuller( (void*&) m_modal_loop );
114
115 m_modal_resultant_parent = aResultantFocusWindow;
116
117 Show( true );
118 Raise(); // Needed on some Window managers to always display the frame
119
120 SetFocus();
121
122 {
123 // Using wxWindowDisabler() has two issues: it will disable top-level windows that are
124 // our *children* (such as sub-frames), and it will disable all context menus we try to
125 // put up. Fortunatly we already had to cross this Rubicon for QuasiModal dialogs, so
126 // we re-use that strategy.
127 wxWindow* parent = GetParent();
128
129 while( parent && !parent->IsTopLevel() )
130 parent = parent->GetParent();
131
132 WINDOW_DISABLER raii_parent_disabler( parent );
133
134 wxGUIEventLoop event_loop;
135 m_modal_loop = &event_loop;
136 event_loop.Run();
137 }
138
139 if( aResult )
140 *aResult = m_modal_string;
141
142 if( aResultantFocusWindow )
143 {
144 aResultantFocusWindow->Raise();
145
146 // have the final say, after wxWindowDisabler reenables my parent and
147 // the events settle down, set the focus
148 wxSafeYield();
149 aResultantFocusWindow->SetFocus();
150 }
151
152 return m_modal_ret_val;
153}
154
155
157{
159
160 return EDA_BASE_FRAME::Destroy();
161}
162
163
165{
166 return !m_modal_loop;
167}
168
169
170void KIWAY_PLAYER::DismissModal( bool aRetVal, const wxString& aResult )
171{
172 m_modal_ret_val = aRetVal;
173 m_modal_string = aResult;
174
175 if( m_modal_loop )
176 {
177 m_modal_loop->Exit();
178 m_modal_loop = nullptr; // this marks it as dismissed.
179 }
180
181 Show( false );
182}
183
184
186{
187 // logging support
188 KiwayMailIn( aEvent ); // call the virtual, override in derived.
189}
190
191
192void KIWAY_PLAYER::CreateServer( int service, bool local )
193{
194 wxIPV4address addr;
195
196 // Set the port number
197 addr.Service( service );
198
199 // Listen on localhost only if requested
200 if( local )
201 addr.Hostname( HOSTNAME );
202
203 if( m_socketServer )
204 {
205 // this helps prevent any events that could come in during deletion
206 m_socketServer->Notify( false );
207 delete m_socketServer;
208 }
209
210 m_socketServer = new wxSocketServer( addr );
211
212 m_socketServer->SetNotify( wxSOCKET_CONNECTION_FLAG );
213 m_socketServer->SetEventHandler( *this, ID_EDA_SOCKET_EVENT_SERV );
214 m_socketServer->Notify( true );
215}
216
217
218void KIWAY_PLAYER::OnSockRequest( wxSocketEvent& evt )
219{
220 size_t len;
221 wxSocketBase* sock = evt.GetSocket();
222
223 switch( evt.GetSocketEvent() )
224 {
225 case wxSOCKET_INPUT:
226 sock->Read( client_ipc_buffer, 1 );
227
228 if( sock->LastCount() == 0 )
229 break; // No data, occurs on opening connection
230
231 sock->Read( client_ipc_buffer + 1, IPC_BUF_SIZE - 2 );
232 len = 1 + sock->LastCount();
233 client_ipc_buffer[len] = 0;
235 break;
236
237 case wxSOCKET_LOST:
238 return;
239 break;
240
241 default:
242 wxLogError( wxT( "EDA_DRAW_FRAME::OnSockRequest() error: Invalid event !" ) );
243 break;
244 }
245}
246
247
248void KIWAY_PLAYER::OnSockRequestServer( wxSocketEvent& evt )
249{
250 wxSocketBase* socket;
251 wxSocketServer* server = (wxSocketServer*) evt.GetSocket();
252
253 socket = server->Accept();
254
255 if( socket == nullptr )
256 return;
257
258 m_sockets.push_back( socket );
259
260 socket->Notify( true );
261 socket->SetEventHandler( *this, ID_EDA_SOCKET_EVENT );
262 socket->SetNotify( wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG );
263}
264
The base frame for deriving all KiCad main window classes.
FRAME_T GetFrameType() const
EDA_BASE_FRAME(wxWindow *aParent, FRAME_T aFrameType, const wxString &aTitle, const wxPoint &aPos, const wxSize &aSize, long aStyle, const wxString &aFrameName, KIWAY *aKiway, const EDA_IU_SCALE &aIuScale)
KIWAY & Kiway() const
Return a reference to the KIWAY that this object has an opportunity to participate in.
Carry a payload from one KIWAY_PLAYER to another within a PROJECT.
Definition kiway_mail.h:38
A wxFrame capable of the OpenProjectFiles function, meaning it can load a portion of a KiCad project.
virtual bool ShowModal(wxString *aResult=nullptr, wxWindow *aResultantFocusWindow=nullptr)
Show this wxFrame as if it were a modal dialog, with all other instantiated wxFrames disabled until t...
wxString m_modal_string
virtual void ExecuteRemoteCommand(const char *cmdline)
Execute a remote command sent via socket (to port KICAD_PCB_PORT_SERVICE_NUMBER, currently 4242).
void CreateServer(int service, bool local=true)
virtual void KiwayMailIn(KIWAY_MAIL_EVENT &aEvent)
Receive #KIWAY_ROUTED_EVENT messages from other players.
wxWindow * m_modal_resultant_parent
KIWAY_PLAYER(KIWAY *aKiway, wxWindow *aParent, FRAME_T aFrameType, const wxString &aTitle, const wxPoint &aPos, const wxSize &aSize, long aStyle, const wxString &aFrameName, const EDA_IU_SCALE &aIuScale)
bool Destroy() override
Our version of Destroy() which is virtual from wxWidgets.
wxGUIEventLoop * m_modal_loop
Points to nested event_loop. NULL means not modal and dismissed.
std::vector< wxSocketBase * > m_sockets
void DismissModal(bool aRetVal, const wxString &aResult=wxEmptyString)
void OnSockRequestServer(wxSocketEvent &evt)
void OnSockRequest(wxSocketEvent &evt)
bool IsModal() const override
Return true if the frame is shown in our modal mode and false if the frame is shown as an usual frame...
void kiway_express(KIWAY_MAIL_EVENT &aEvent)
Event handler, routes to derivative specific virtual KiwayMailIn().
wxSocketServer * m_socketServer
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
Definition kiway.h:295
void PlayerDidClose(FRAME_T aFrameType)
Notifies a Kiway that a player has been closed.
Definition kiway.cpp:499
Definition raii.h:38
Temporarily disable a window, and then re-enable on destruction.
Definition raii.h:87
static const wxString HOSTNAME(wxT("localhost"))
FRAME_T
The set of EDA_BASE_FRAME derivatives, typically stored in EDA_BASE_FRAME::m_Ident.
Definition frame_type.h:33
@ ID_EDA_SOCKET_EVENT
Definition id.h:133
@ ID_EDA_SOCKET_EVENT_SERV
Definition id.h:132
#define EVT_KIWAY_EXPRESS(func)
Event table definition for the KIWAY_ROUTED_EVENT event class.
Definition kiway_mail.h:78
#define IPC_BUF_SIZE
static char client_ipc_buffer[IPC_BUF_SIZE]
static const wxString HOSTNAME(wxT("localhost"))
This file contains miscellaneous commonly used macros and functions.