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