1 // Copyright (C) 2015-2017 Phil Rosenberg
2 // Copyright (C) 2017 Alan W. Irwin
3 //
4 // This file is part of PLplot.
5 //
6 // PLplot is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU Library General Public License as published
8 // by the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
10 //
11 // PLplot is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU Library General Public License for more details.
15 //
16 // You should have received a copy of the GNU Library General Public License
17 // along with PLplot; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 //
20
21 #include "wxplframe.h"
22 #include <wx/menu.h>
23 #include <wx/msgdlg.h>
24 // Needed for cerr and endl below
25 #include <iostream>
26
27 // If want to test IPC speed without plotting anything.
28 //#define PLPLOT_WX_NOPLOT
29
30 const int wxPlFrame::ID_FILE_EXIT = ::wxNewId();
31 const int wxPlFrame::ID_HELP_ABOUT = ::wxNewId();
32 const int wxPlFrame::ID_PAGE_NEXT = ::wxNewId();
33 const int wxPlFrame::ID_PAGE_PREV = ::wxNewId();
34 const int wxPlFrame::ID_PAGE_FIXASPECT = ::wxNewId();
35 const int wxPlFrame::ID_CHECK_TIMER = ::wxNewId();
36
37
BEGIN_EVENT_TABLE(wxPlFrame,wxPLplotwindow<wxFrame>)38 BEGIN_EVENT_TABLE( wxPlFrame, wxPLplotwindow<wxFrame> )
39 EVT_MENU( ID_FILE_EXIT, wxPlFrame::OnExit )
40 EVT_MENU( ID_HELP_ABOUT, wxPlFrame::OnAbout )
41 EVT_MENU( ID_PAGE_FIXASPECT, wxPlFrame::OnToggleFixAspect )
42 EVT_MENU( ID_PAGE_NEXT, wxPlFrame::OnNextPage )
43 EVT_MENU( ID_PAGE_PREV, wxPlFrame::OnPrevPage )
44 EVT_TIMER( ID_CHECK_TIMER, wxPlFrame::OnCheckTimer )
45 EVT_KEY_DOWN( wxPlFrame::OnKey )
46 EVT_LEFT_UP( wxPlFrame::OnMouse )
47 EVT_MOUSE_EVENTS( wxPlFrame::OnMouse )
48 END_EVENT_TABLE()
49
50
51 wxPlFrame::wxPlFrame( wxWindow *parent, wxWindowID id, const wxString &title, wxString file, long fileSize,
52 const wxPoint &pos, const wxSize &size, long style, const wxString &name )
53 : wxPLplotwindow<wxFrame>( true, size, 1000 ), m_checkTimer( this, ID_CHECK_TIMER )
54 {
55 wxFrame::Create( parent, id, title, pos, wxDefaultSize, style, name );
56 setupMenus();
57
58 m_viewingPage = 0;
59 m_writingPage = 0;
60 m_file = file;
61 m_fileSize = fileSize;
62 m_inCheckTimerFunction = false;
63 m_nothingToDoCounter = 0;
64
65 if ( file.length() > 0 )
66 {
67 m_memoryMap.create( file.mb_str(), m_fileSize, true, false );
68 if ( m_memoryMap.isValid() )
69 {
70 #ifdef PL_WXWIDGETS_IPC3
71 m_memoryMap.initializeSemaphoresToValid( file.mb_str() );
72
73 #else // #ifdef PL_WXWIDGETS_IPC3
74 wxString mutexName = file + wxT( "mut" );
75 m_mutex.create( mutexName.mb_str() );
76 if ( !m_mutex.isValid() )
77 m_memoryMap.close();
78 #endif
79 }
80 }
81 if ( !m_memoryMap.isValid() )
82 {
83 throw ( "Error initializing the shared memory and/or mutex needed for the application. The application will close" );
84 }
85
86 m_locateModePage = -1;
87 m_transferComplete = false;
88 m_plottedBufferAmount = 0;
89 //signal that we have opened the shared memory
90 #ifdef PL_WXWIDGETS_IPC3
91 try
92 {
93 // Initialize all of m_header to beat valgrind uninitialized noise with
94 // shared memory definitions of m_header.
95
96 // This is actually an invalid value that if not overwritten
97 // by the -dev wxwidgets side would throw an exception later on.
98 m_header.transmissionType = transmissionRegular;
99 // Sensible default
100 m_header.plbufAmountToTransmit = 0;
101 // This one let's -dev wxwidgets know we have made contact
102 m_header.viewerOpenFlag = 1;
103 // Sensible default
104 m_header.locateModeFlag = 0;
105 // Sensible default
106 m_header.completeFlag = 0;
107 // We leave uninitialized, the graphicsIn and textSizeInfo structs
108 // that are part of m_header.
109 #ifdef PLPLOT_WX_DEBUG_OUTPUT
110 std::cerr << "Before transmitBytes" << std::endl;
111 std::cerr << "transmissionType = " << static_cast<unsigned int>( m_header.transmissionType ) << std::endl;
112 std::cerr << "plbufAmountToTransmit = " << m_header.plbufAmountToTransmit << std::endl;
113 std::cerr << "viewerOpenFlag = " << m_header.viewerOpenFlag << std::endl;
114 std::cerr << "locateModeFlag = " << m_header.locateModeFlag << std::endl;
115 std::cerr << "completeFlag = " << m_header.completeFlag << std::endl;
116 #endif // #ifdef PLPLOT_WX_DEBUG_OUTPUT
117 m_memoryMap.transmitBytes( true, &m_header, sizeof ( MemoryMapHeader ) );
118 }
119 catch ( const char *message )
120 {
121 std::cerr << "Caught exception when attempting to signal that we have opened the shared memory. The message was " << message << std::endl;
122 throw( 1 );
123 }
124
125 catch ( ... )
126 {
127 std::cerr << "Caught unknown exception when attempting to signal that we have opened the shared memory" << std::endl;
128 throw( 1 );
129 }
130 #else // #ifdef PL_WXWIDGETS_IPC3
131 MemoryMapHeader *header = (MemoryMapHeader *) ( m_memoryMap.getBuffer() );
132 header->viewerOpenFlag = 1;
133 #endif // #ifdef PL_WXWIDGETS_IPC3
134 m_checkTimer.Start( m_idleTimerInterval );
135 }
136
setupMenus()137 void wxPlFrame::setupMenus()
138 {
139 wxMenuBar* mbar = new wxMenuBar();
140
141 wxMenu * fileMenu = new wxMenu( wxT( "" ) );
142 fileMenu->Append( ID_FILE_EXIT, wxT( "E&xit\tAlt+F4" ), wxT( "Exit the application" ) );
143 mbar->Append( fileMenu, wxT( "&File" ) );
144
145
146 wxMenu * pageMenu = new wxMenu( wxT( "" ) );
147 wxMenuItem *aspectMenuItem = new wxMenuItem( pageMenu, ID_PAGE_FIXASPECT, wxT( "Fix Aspect" ),
148 wxT( "Fix the aspect ratio of the plot" ), wxITEM_CHECK );
149 pageMenu->Append( aspectMenuItem );
150 aspectMenuItem->Check( true );
151 pageMenu->Append( ID_PAGE_PREV, wxT( "Previous\tPgUp" ), wxT( "Move to the previous page" ) );
152 pageMenu->Append( ID_PAGE_NEXT, wxT( "Next\tEnter" ), wxT( "Move to the next page" ) );
153 mbar->Append( pageMenu, wxT( "&Page" ) );
154
155 wxMenu* helpMenu = new wxMenu( wxT( "" ) );
156 helpMenu->Append( ID_HELP_ABOUT, wxT( "&About\tF1" ), wxT( "Show info about this application" ) );
157 mbar->Append( helpMenu, wxT( "&Help" ) );
158
159 SetMenuBar( mbar );
160
161 m_stream.SetFixedAspectRatio( aspectMenuItem->IsChecked() );
162 }
163
OnExit(wxCommandEvent & event)164 void wxPlFrame::OnExit( wxCommandEvent& event )
165 {
166 Close();
167 }
168
OnAbout(wxCommandEvent & event)169 void wxPlFrame::OnAbout( wxCommandEvent& event )
170 {
171 wxMessageBox( wxT( "wxPlViewer version 1.00.0" ), wxT( "About wxPlViewer..." ) );
172 }
173
~wxPlFrame()174 wxPlFrame::~wxPlFrame()
175 {
176 }
177
OnCheckTimer(wxTimerEvent & event)178 void wxPlFrame::OnCheckTimer( wxTimerEvent &event )
179 {
180 #ifdef PL_WXWIDGETS_IPC3
181 try
182 {
183 // call ReadTransmission once which should stop timer
184 // and return false
185 if ( ReadTransmission() )
186 throw ( "wxPlFrame::OnCheckTimer (internal error): ReadTransmission should always return false" );
187 }
188 catch ( const char *message )
189 {
190 std::cerr << "Caught exception in wxPlFrame::OnCheckTimer. The message was " << message << std::endl;
191 throw( 1 );
192 }
193
194 catch ( ... )
195 {
196 std::cerr << "Caught unknown exception in wxPlFrame::OnCheckTimer" << std::endl;
197 throw( 1 );
198 }
199
200 #else // #ifdef PL_WXWIDGETS_IPC3
201 //repeatedly call ReadTransmission until there is nothing
202 //left to read
203 PLINT nFalses = 0;
204 while ( nFalses < 100 )
205 {
206 if ( ReadTransmission() )
207 nFalses = 0;
208 else
209 {
210 ++nFalses;
211 wxMilliSleep( 1 );
212 }
213 }
214 #endif // #ifdef PL_WXWIDGETS_IPC3
215 }
216
217 //This function reads any transmissions from the shared memory and acts upon
218 //it. If there was nothing to read it returns false, otherwise it returns
219 //true indicating that the program may want to read some more.
ReadTransmission()220 bool wxPlFrame::ReadTransmission()
221 {
222 //avoid re-entrant behaviour if some function yields allowing the
223 //timer to call this function again
224 if ( m_inCheckTimerFunction )
225 return true;
226 m_inCheckTimerFunction = true;
227
228 if ( !m_memoryMap.isValid() )
229 throw( "wxPlFrame::ReadTransmission: invalid Memory map" );
230
231 #ifdef PL_WXWIDGETS_IPC3
232 size_t nbytes;
233 // Read the entire plbuf generated by a series of calls on the writer (-dev wxwidgets)
234 // side to transmitBuffer, which writes a header and optionally a sequential
235 // part or all of plbuf per each call. The end of that series of calls
236 // is signalled by the writer side setting m_header.completeFlag to a non-zero value.
237
238 do
239 {
240 // First read complete data header to find out everything we need to know
241 // about the transmitBuffer call.
242 m_memoryMap.receiveBytes( true, &m_header, sizeof ( MemoryMapHeader ) );
243 #ifdef PLPLOT_WX_DEBUG_OUTPUT
244 std::cerr << "After receiveBytes" << std::endl;
245 std::cerr << "transmissionType = " << static_cast<unsigned int>( m_header.transmissionType ) << std::endl;
246 std::cerr << "plbufAmountToTransmit = " << m_header.plbufAmountToTransmit << std::endl;
247 std::cerr << "viewerOpenFlag = " << m_header.viewerOpenFlag << std::endl;
248 std::cerr << "locateModeFlag = " << m_header.locateModeFlag << std::endl;
249 std::cerr << "completeFlag = " << m_header.completeFlag << std::endl;
250 #endif // #ifdef PLPLOT_WX_DEBUG_OUTPUT
251 switch ( m_header.transmissionType )
252 {
253 // Three valid cases which should be handled after plbuf has been received and processed.
254 case transmissionEndOfPage:
255 case transmissionEndOfPageNoPause:
256 case transmissionLocate:
257 break;
258 // Other valid cases which should be handled before plbuf has been received and processed.
259 #if 0
260 case transmissionRequestTextSize:
261 wxClientDC dc( this );
262 wxCoord width;
263 wxCoord height;
264 wxCoord depth;
265 wxCoord leading;
266 wxFont *font = wxTheFontList->FindOrCreateFont( m_header.textSizeInfo.pt, m_header.textSizeInfo.family,
267 m_header.textSizeInfo.style, m_header.textSizeInfo.weight, m_header.textSizeInfo.underlined );
268 dc.GetTextExtent( wxString( m_header.textSizeInfo.text ), &width, &height, &depth, &leading, font );
269 m_header.textSizeInfo.width = long(width);
270 m_header.textSizeInfo.height = long(height);
271 m_header.textSizeInfo.depth = long(depth);
272 m_header.textSizeInfo.leading = long(leading);
273 m_header.textSizeInfo.written = true;
274 break;
275 #endif // #if 0
276 // Used only to transmit m_header.completeFlag != 0 to terminate this loop
277 case transmissionComplete:
278 // Used only for flush.
279 case transmissionFlush:
280 break;
281 case transmissionClose:
282 Close( 0 );
283 break;
284 case transmissionBeginPage:
285 m_pageBuffers.resize( m_pageBuffers.size() + 1 );
286 m_bufferValidFlags.push_back( false );
287 m_writingPage = m_pageBuffers.size() - 1;
288 break;
289
290 // Invalid cases.
291 default:
292 throw( "wxPlFrame::ReadTransmission: read invalid value of transmissionType" );
293 break;
294 }
295
296 if ( m_header.plbufAmountToTransmit > 0 )
297 {
298 char * plbufBuffer = (char *) malloc( m_header.plbufAmountToTransmit );
299 if ( plbufBuffer == NULL )
300 throw( "wxPlFrame::ReadTransmission: malloc of plbufBuffer failed" );
301 m_memoryMap.receiveBytes( false, plbufBuffer, m_header.plbufAmountToTransmit );
302 #ifdef PLPLOT_WX_DEBUG_OUTPUT
303 std::cerr << "Successful read of plbuf" << std::endl;
304 #endif // #ifdef PLPLOT_WX_DEBUG_OUTPUT
305 #ifndef PLPLOT_WX_NOPLOT
306 m_pageBuffers[m_writingPage].insert( m_pageBuffers[m_writingPage].end(),
307 plbufBuffer, plbufBuffer + m_header.plbufAmountToTransmit );
308 #endif // #ifndef PLPLOT_WX_NOPLOT
309 m_bufferValidFlags[m_writingPage] = true;
310 // Conditionally plot buffer, but I (AWI) have no clue where the 1024 below
311 // comes from.
312 if ( m_writingPage == m_viewingPage &&
313 ( m_plottedBufferAmount + 1024 ) < m_pageBuffers[ m_writingPage ].size() )
314 SetPageAndUpdate();
315 free( plbufBuffer );
316 }
317 if ( m_header.transmissionType == transmissionEndOfPage || m_header.transmissionType == transmissionEndOfPageNoPause )
318 {
319 // N.B. can receive (e.g., example 2) two transmissionEndOfPage commands in a row
320 // with the second one having m_header.plbufAmountToTransmit == 0. But I assume
321 // SetPageAndUpdate should be able to handle this case.
322 if ( m_header.transmissionType == transmissionEndOfPage )
323 SetPageAndUpdate();
324 else
325 SetPageAndUpdate( m_writingPage );
326 }
327 if ( m_header.transmissionType == transmissionLocate )
328 {
329 SetPageAndUpdate();
330 m_locateModePage = m_writingPage;
331 }
332 }
333 while ( !( m_header.transmissionType == transmissionLocate || m_header.completeFlag != 0 || m_header.transmissionType == transmissionRequestTextSize || m_header.transmissionType == transmissionFlush ) );
334
335 if ( m_header.completeFlag != 0 )
336 {
337 //Once the complete flag is set to non-zero then stop looking
338 m_transferComplete = true;
339 m_checkTimer.Stop();
340 }
341 else if ( m_currentTimerInterval != m_busyTimerInterval )
342 {
343 //If we have something to read then make sure
344 //we keep checking regularly for more
345 m_checkTimer.Stop();
346 m_checkTimer.Start( m_busyTimerInterval );
347 m_currentTimerInterval = m_busyTimerInterval;
348 m_nothingToDoCounter = 0;
349 }
350
351 if ( m_header.locateModeFlag != 0 )
352 {
353 //Stop checking for new data if we are in locate mode.
354 //This is a workaround for a hang situation which occurs
355 //with the IPC3 comms when bot the viewer and the core
356 //code end up stuck waiting for new data.
357 //This should be removed when that hang situation is
358 //removed by including a timeout option for the
359 //receiveData function.
360 m_checkTimer.Stop();
361 }
362
363 // Allow the timer to call this function again
364 m_inCheckTimerFunction = false;
365
366 // Always return false.
367 return false;
368
369 #else // #ifdef PL_WXWIDGETS_IPC3
370 MemoryMapHeader *header = (MemoryMapHeader *) ( m_memoryMap.getBuffer() );
371 //lock the mutex for the duration of this scope
372 PLNamedMutexLocker locker( &m_mutex );
373 //Check if there is anything to read
374 if ( header->readLocation == header->writeLocation )
375 {
376 ++m_nothingToDoCounter;
377 if ( header->completeFlag != 0 )
378 {
379 //if there is nothing to read and the complete flag is set then
380 // stop looking
381 m_transferComplete = true;
382 m_checkTimer.Stop();
383 }
384 else if ( m_currentTimerInterval != m_idleTimerInterval && m_nothingToDoCounter > m_nothingToDoCounterLimit )
385 {
386 //if there is nothing to read but we might have more to come
387 //then check less frequently
388 m_checkTimer.Stop();
389 m_checkTimer.Start( m_idleTimerInterval );
390 m_currentTimerInterval = m_idleTimerInterval;
391 }
392
393 //nothing to do so return
394 m_inCheckTimerFunction = false;
395 return false;
396 }
397
398 if ( m_currentTimerInterval != m_busyTimerInterval )
399 {
400 //If we have something to read then make sure
401 //we keep checking regularly for more
402 m_checkTimer.Stop();
403 m_checkTimer.Start( m_busyTimerInterval );
404 m_currentTimerInterval = m_busyTimerInterval;
405 m_nothingToDoCounter = 0;
406 }
407
408 unsigned char transmissionType;
409 transmissionType = *( (unsigned char *) ( m_memoryMap.getBuffer() + header->readLocation ) );
410 size_t nRead = sizeof ( unsigned char );
411
412 if ( transmissionType == transmissionSkipFileEnd )
413 {
414 header->readLocation = plMemoryMapReservedSpace;
415 m_inCheckTimerFunction = false;
416 return true;
417 }
418 else if ( transmissionType == transmissionBeginPage )
419 {
420 m_pageBuffers.resize( m_pageBuffers.size() + 1 );
421 m_bufferValidFlags.push_back( false );
422 m_writingPage = m_pageBuffers.size() - 1;
423 }
424 else if ( transmissionType == transmissionEndOfPage || transmissionType == transmissionEndOfPageNoPause )
425 {
426 if ( !m_bufferValidFlags[m_writingPage] )
427 throw( "Received an end of page transmission after an incomplete or no draw instruction" );
428 if ( transmissionType == transmissionEndOfPage )
429 SetPageAndUpdate();
430 else
431 SetPageAndUpdate( m_writingPage );
432 }
433 else if ( transmissionType == transmissionLocate )
434 {
435 SetPageAndUpdate();
436 m_locateModePage = m_writingPage;
437 }
438 else if ( transmissionType == transmissionRequestTextSize )
439 {
440 wxClientDC dc( this );
441 wxCoord width;
442 wxCoord height;
443 wxCoord depth;
444 wxCoord leading;
445 wxFont *font = wxTheFontList->FindOrCreateFont( header->textSizeInfo.pt, header->textSizeInfo.family,
446 header->textSizeInfo.style, header->textSizeInfo.weight, header->textSizeInfo.underlined );
447 dc.GetTextExtent( wxString( header->textSizeInfo.text ), &width, &height, &depth, &leading, font );
448 header->textSizeInfo.width = long(width);
449 header->textSizeInfo.height = long(height);
450 header->textSizeInfo.depth = long(depth);
451 header->textSizeInfo.leading = long(leading);
452 header->textSizeInfo.written = true;
453 }
454 else if ( transmissionType == transmissionPartial || transmissionType == transmissionComplete )
455 {
456 size_t dataSize;
457 dataSize = *(size_t *) ( (unsigned char *) ( m_memoryMap.getBuffer() + header->readLocation +
458 sizeof ( transmissionType ) ) );
459 #ifndef PLPLOT_WX_NOPLOT
460 m_pageBuffers[m_writingPage].insert( m_pageBuffers[m_writingPage].end(),
461 m_memoryMap.getBuffer() + header->readLocation + sizeof ( transmissionType ) + sizeof ( dataSize ),
462 m_memoryMap.getBuffer() + header->readLocation + sizeof ( transmissionType ) + sizeof ( dataSize ) + dataSize );
463 #endif // #ifndef PLPLOT_WX_NOPLOT
464 nRead += sizeof ( dataSize ) + dataSize;
465 if ( transmissionType == transmissionComplete )
466 m_bufferValidFlags[m_writingPage] = true;
467 else
468 m_bufferValidFlags[m_writingPage] = false;
469
470 // If we have a new unplotted buffer, then it is due to either
471 // a flush or we have so much data we have wrapped the buffer.
472 if ( m_writingPage == m_viewingPage &&
473 ( m_plottedBufferAmount + 1024 ) < m_pageBuffers[ m_writingPage ].size() )
474 SetPageAndUpdate();
475 }
476 else if ( transmissionType == transmissionClose )
477 {
478 Close( 0 );
479 }
480 header->readLocation += nRead;
481 if ( header->readLocation == m_memoryMap.getSize() )
482 header->readLocation = plMemoryMapReservedSpace;
483 m_inCheckTimerFunction = false;
484 return true;
485 #endif //#ifdef PL_WXWIDGETS_IPC3
486 }
OnToggleFixAspect(wxCommandEvent & event)487 void wxPlFrame::OnToggleFixAspect( wxCommandEvent &event )
488 {
489 fixAspect( event.IsChecked() );
490 }
491
fixAspect(bool fix)492 void wxPlFrame::fixAspect( bool fix )
493 {
494 m_stream.SetFixedAspectRatio( fix );
495 if ( !fix )
496 this->Refresh();
497 }
SetClientSize(int width,int height)498 void wxPlFrame::SetClientSize( int width, int height )
499 {
500 wxFrame::SetClientSize( width, height );
501 m_stream.SetSize( width, height );
502 }
503
SetClientSize(const wxSize & size)504 void wxPlFrame::SetClientSize( const wxSize &size )
505 {
506 SetClientSize( size.GetWidth(), size.GetHeight() );
507 }
508
SetClientSize(const wxRect & rect)509 void wxPlFrame::SetClientSize( const wxRect &rect )
510 {
511 SetClientSize( rect.GetWidth(), rect.GetHeight() );
512 }
513
OnNextPage(wxCommandEvent & event)514 void wxPlFrame::OnNextPage( wxCommandEvent& event )
515 {
516 SetPageAndUpdate( m_viewingPage + 1 );
517 }
518
OnPrevPage(wxCommandEvent & event)519 void wxPlFrame::OnPrevPage( wxCommandEvent& event )
520 {
521 SetPageAndUpdate( m_viewingPage - 1 );
522 }
523
OnMouse(wxMouseEvent & event)524 void wxPlFrame::OnMouse( wxMouseEvent &event )
525 {
526 //save the mouse position for use in key presses
527 m_cursorPosition = event.GetPosition();
528
529 //If the mouse button was clicked then
530 if ( m_locateModePage == m_viewingPage && event.ButtonDown() || event.ButtonUp() )
531 {
532 wxSize clientSize = GetClientSize();
533 #ifdef PL_WXWIDGETS_IPC3
534 m_header.graphicsIn.pX = m_cursorPosition.x;
535 m_header.graphicsIn.pY = m_cursorPosition.y;
536 m_header.graphicsIn.dX = PLFLT( m_cursorPosition.x + 0.5 ) / PLFLT( clientSize.GetWidth() );
537 m_header.graphicsIn.dY = 1.0 - PLFLT( m_cursorPosition.y + 0.5 ) / PLFLT( clientSize.GetHeight() );
538
539 int button = event.GetButton();
540
541 if ( button == wxMOUSE_BTN_LEFT )
542 m_header.graphicsIn.button = 1;
543 else if ( button == wxMOUSE_BTN_MIDDLE )
544 m_header.graphicsIn.button = 2;
545 else if ( button == wxMOUSE_BTN_RIGHT )
546 m_header.graphicsIn.button = 3;
547 else if ( button == wxMOUSE_BTN_AUX1 )
548 m_header.graphicsIn.button = 4;
549 else if ( button == wxMOUSE_BTN_AUX2 )
550 m_header.graphicsIn.button = 5;
551
552 //flags the buttons that were down before this event
553 m_header.graphicsIn.state = 0;
554 if ( ( event.LeftIsDown() && !event.LeftDown() ) || event.LeftUp() )
555 m_header.graphicsIn.state |= ( 1 << 8 );
556 if ( ( event.MiddleIsDown() && !event.MiddleDown() ) || event.MiddleUp() )
557 m_header.graphicsIn.state |= ( 1 << 9 );
558 if ( ( event.RightIsDown() && !event.RightDown() ) || event.RightUp() )
559 m_header.graphicsIn.state |= ( 1 << 10 );
560 if ( ( event.Aux1IsDown() && !event.Aux1Down() ) || event.Aux1Up() )
561 m_header.graphicsIn.state |= ( 1 << 11 );
562 if ( ( event.Aux2IsDown() && !event.Aux2Down() ) || event.Aux2Up() )
563 m_header.graphicsIn.state |= ( 1 << 12 );
564
565 m_header.graphicsIn.keysym = 0x20; // keysym for button event from xwin.c
566
567 m_header.locateModeFlag = 0;
568 m_memoryMap.transmitBytes( true, &m_header, sizeof ( MemoryMapHeader ) );
569 m_locateModePage = -1;
570
571 //Restart checking for new data now locate mode is complete.
572 //This is a workaround for a hang situation which occurs
573 //with the IPC3 comms when bot the viewer and the core
574 //code end up stuck waiting for new data.
575 //This should be removed when that hang situation is
576 //removed by including a timeout option for the
577 //receiveData function.
578 m_checkTimer.Start();
579 #else // #ifdef PL_WXWIDGETS_IPC3
580 PLNamedMutexLocker locker( &m_mutex );
581 MemoryMapHeader *header = (MemoryMapHeader *) m_memoryMap.getBuffer();
582 //PLGraphicsIn & graphicsIn = header->graphicsIn;
583 header->graphicsIn.pX = m_cursorPosition.x;
584 header->graphicsIn.pY = m_cursorPosition.y;
585 header->graphicsIn.dX = PLFLT( m_cursorPosition.x + 0.5 ) / PLFLT( clientSize.GetWidth() );
586 header->graphicsIn.dY = 1.0 - PLFLT( m_cursorPosition.y + 0.5 ) / PLFLT( clientSize.GetHeight() );
587
588 int button = event.GetButton();
589
590 if ( button == wxMOUSE_BTN_LEFT )
591 header->graphicsIn.button = 1;
592 else if ( button == wxMOUSE_BTN_MIDDLE )
593 header->graphicsIn.button = 2;
594 else if ( button == wxMOUSE_BTN_RIGHT )
595 header->graphicsIn.button = 3;
596 else if ( button == wxMOUSE_BTN_AUX1 )
597 header->graphicsIn.button = 4;
598 else if ( button == wxMOUSE_BTN_AUX2 )
599 header->graphicsIn.button = 5;
600
601 //flags the buttons that were down before this event
602 header->graphicsIn.state = 0;
603 if ( ( event.LeftIsDown() && !event.LeftDown() ) || event.LeftUp() )
604 header->graphicsIn.state |= ( 1 << 8 );
605 if ( ( event.MiddleIsDown() && !event.MiddleDown() ) || event.MiddleUp() )
606 header->graphicsIn.state |= ( 1 << 9 );
607 if ( ( event.RightIsDown() && !event.RightDown() ) || event.RightUp() )
608 header->graphicsIn.state |= ( 1 << 10 );
609 if ( ( event.Aux1IsDown() && !event.Aux1Down() ) || event.Aux1Up() )
610 header->graphicsIn.state |= ( 1 << 11 );
611 if ( ( event.Aux2IsDown() && !event.Aux2Down() ) || event.Aux2Up() )
612 header->graphicsIn.state |= ( 1 << 12 );
613
614 header->graphicsIn.keysym = 0x20; // keysym for button event from xwin.c
615
616 header->locateModeFlag = 0;
617 m_locateModePage = -1;
618 #endif // #ifdef PL_WXWIDGETS_IPC3
619 }
620 }
621
OnKey(wxKeyEvent & event)622 void wxPlFrame::OnKey( wxKeyEvent &event )
623 {
624 #ifndef PL_WXWIDGETS_IPC3
625 //This only works on Windows, unfortunately on wxGTK, wxFrames cannot catch key presses
626 if ( m_locateModePage = m_viewingPage )
627 {
628 PLNamedMutexLocker locker( &m_mutex );
629 MemoryMapHeader *header = (MemoryMapHeader *) m_memoryMap.getBuffer();
630
631 wxSize clientSize = GetClientSize();
632
633 header->graphicsIn.pX = m_cursorPosition.x;
634 header->graphicsIn.pY = m_cursorPosition.y;
635 header->graphicsIn.dX = PLFLT( m_cursorPosition.x + 0.5 ) / PLFLT( clientSize.GetWidth() );
636 header->graphicsIn.dY = 1.0 - PLFLT( m_cursorPosition.y + 0.5 ) / PLFLT( clientSize.GetHeight() );
637 // gin->state = keyEvent->state;
638
639 int keycode = event.GetKeyCode();
640 header->graphicsIn.string[0] = (char) keycode;
641 header->graphicsIn.string[1] = '\0';
642
643 // ESCAPE, RETURN, etc. are already in ASCII equivalent
644 header->graphicsIn.keysym = keycode;
645
646 header->locateModeFlag = 0;
647 m_locateModePage = -1;
648 }
649 #endif //#ifndef PL_WXWIDGETS_IPC3
650 }
651
SetPageAndUpdate(size_t page)652 void wxPlFrame::SetPageAndUpdate( size_t page )
653 {
654 //if we get a page of -1 (which will really be max size_t) then just update the current page
655 //otherwise switch to the given page
656 if ( page != size_t( -1 ) )
657 {
658 if ( page >= m_pageBuffers.size() )
659 {
660 if ( m_transferComplete )
661 Close();
662 return;
663 }
664 if ( page != m_viewingPage )
665 {
666 m_viewingPage = page;
667 m_plottedBufferAmount = 0;
668 }
669 }
670
671 // If there is an unplotted buffer and the buffer is valid
672 // (contains some instructions and ends with a valid instruction)
673 // then send that buffer to the driver and replot the page.
674 if ( m_bufferValidFlags[m_viewingPage] && m_plottedBufferAmount < m_pageBuffers[m_viewingPage].size() )
675 {
676 if ( m_plottedBufferAmount == 0 )
677 //this ensures that any buffer generated by plplot initialisation is overwritten
678 //often there is a begin page already in the buffer by the time we get here
679 GetStream()->ImportBuffer( &m_pageBuffers[m_viewingPage][0], m_pageBuffers[m_viewingPage].size() );
680 else
681 GetStream()->AppendBuffer( &m_pageBuffers[m_viewingPage][m_plottedBufferAmount], m_pageBuffers[m_viewingPage].size() - m_plottedBufferAmount );
682 m_plottedBufferAmount = m_pageBuffers[m_viewingPage].size();
683 Refresh();
684 }
685 }
686