Hi Phil, Alan

I started a new thread, that summarizes all the learnings we have so far on 
this and proposes a simple solution that keeps the current API (templates).

1) remotely or in place

First the issue of accessing the machine remotely or in place.
One of my machines that I previously accessed remotely is a server on my living 
room (not very remote in this case).
So I did a test "in place" (that is, directly on the laptop) on this machine.

It was a good idea that I committed a version that only shows the bug, with 
debug messages.
To get that version I did:

git log --pretty=oneline  -n 20
git log - n 20

and that commit it's this one

commit 3cccca6a49a572e7aa518a5b8a6bbecd9ef1f812
Author: Pedro Vicente <pedro.vice...@rhw9121.star1.nesdis.noaa.gov>
Date:   Fri Dec 16 11:24:23 2016 -0500

    wxwidgets binding: insert debug messages
    
    Add debug messages that show sequence of events for a bug that happens
    on some but not all Linux distributions with wxwidgets3.0/3.1.  The
    cause is that frame->Create does not always trigger an OnCreate()
    event on time before the Plot() call.

so I did 

git checkout  3cccca6a49a572e7aa518a5b8a6bbecd9ef1f812
cmake .. -DBUILD_TEST=ON 
make VERBOSE=1 test_wxPLplotDemo

and the output shows the NULL stream

22:35:26: Debug: wxPLplotwindow::wxPLplotwindow
22:35:26: Debug: frame->Create
22:35:26: Debug: pls NULL
22:35:26: Debug: wxPLplotwindow::OnCreate

So, this clearly shows that the bug happens "in place" and we can forget about 
remote X server tests.

2) the infinite Yielding loop 

The introduction of the Yield() call was an unsuccessful attempt to wait for 
the delay
in the OnCreate() event.
But it does not work, and does not fix the bug, and furthermore happens in 
cases where
the bug did not show up (i.e Alan's cases).
So, the Yield() call should be completely removed.

3) The solution for the bug

The solution for the bug is simple and minimal.
It is to override the Create() function of wxPLplotwindow, 
which I did with the following function

template<class WXWINDOW>
bool wxPLplotwindow<WXWINDOW>::Create(wxWindow *parent, wxWindowID id, const 
wxString& title, const wxPoint& pos, const wxSize& size, long style, const 
wxString& name)
{
  PLPLOT_wxLogDebug("wxPLplotwindow::Create()");
  if (!WXWINDOW::Create(parent, id, title, pos, size, style, name))
    return false;
  CreateStream();
  return true;
}

where
CreateStream();
is just a new function that has the code previously in OnCreate()

NOTE:  OnCreate() *ALSO* calls
CreateStream();
because this is used by the PLviewer.
 

Attached to this email is a git patch that can be applied to the current git 
master.
( I did not write a full description)
Also I attached the 2 source files that fix the issue.

NOTE: The change in wxPLplotDemo.cpp was just to remove the Yield() call.
besides that, its use was like it was on 5.11.1, which is

wxPLplotwindow<wxFrame> *frame = new wxPlDemoFrame();
frame->Create( NULL, wxID_ANY, wxT( "wxPLplotDemo" ));
frame->Show();
Plot( frame );

The thing here is that now this call
frame->Create

*creates* the frame immediately, instead of waiting for the OnCreate() event

So, problem solved :-)

@Alan

With this in mind here's a new description for the fix,
similar to the previous, except that it removes the mention of template removal:


"Fixed a bug that happened in test_wxPLplotDemo for  some Linux 
configurations.
 The effect of the bug was a segmentation fault, due to the fact that an 
invalid
plot stream pointer was used. The cause of the stream pointer being invalid
is that the frame window did not initialize in a timely manner. This 
behaviour is a
wxWidgets feature that can or cannot happen in GTK/X11 window systems.
The solution for test_wxPLplotDemo was to initialize the stream in the 
function
Create(), which is done immediately, instead of doing it on the function 
OnCreate(),
that is called later and executed at an indeterminate time. Note: the 
request of creating
the stream in OnCreate() is still present, because this is a feature of the 
driver needed elsewhere."


@Phil, 
do you agree with this solution?

It keeps the current use of templates.
One small caveat is that I think you can only instantiate the template with a 
class that has this Create()
signature 

Create(wxWindow *parent, wxWindowID id, const wxString& title, const wxPoint& 
pos, const wxSize& size, long style, const wxString& name)

which is of course , wxFrames, the current use.
Probably dialogs too, but maybe not things like buttons and other GUI elements.
But I assume that the vast majority of users, if not all, draws the plot in 
"regular" windows?.

-Pedro


Attachment: 0001-Add-function-Create.patch.tar.gz
Description: GNU Zip compressed data

// Copyright (C) 2005  Werner Smekal
//
// This file is part of PLplot.
//
// PLplot is free software; you can redistribute it and/or modify
// it under the terms of the GNU Library General Public License as published
// by the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// PLplot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public License
// along with PLplot; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
//

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
    #pragma hdrstop
#endif

#ifndef WX_PRECOMP
    #include "wx/wx.h"
#endif

#ifdef __WXMAC__
        #include <Carbon/Carbon.h>
extern "C" { void CPSEnableForegroundOperation( ProcessSerialNumber* psn ); }
#endif

#include "wxPLplotwindow.h"
#include <cmath>

#define MAX( a, b )    ( ( a ) < ( b ) ? ( b ) : ( a ) )
#define MIN( a, b )    ( ( a ) < ( b ) ? ( a ) : ( b ) )

// Application icon as XPM
// This free icon was taken from http://2pt3.com/news/twotone-icons-for-free/
static const char            *graph[] = {
// columns rows colors chars-per-pixel
    "16 16 4 2",
    "   c black",
    ".  c #BA1825",
    "X  c gray100",
    "UX c None",
// pixels
    "UX. . . . . . . . . . . . . . UX",
    ". . . . . . . . . . . . . . . . ",
    ". . . . . . . . . . . . . . . . ",
    ". . . . . . . . . . . X X . . . ",
    ". . . . . . . . . . . X X . . . ",
    ". . . . . . . . . . . X X . . . ",
    ". . . . . X X . . . . X X . . . ",
    ". . . . . X X . . . . X X . . . ",
    ". . . . . X X . X X . X X . . . ",
    ". . . . . X X . X X . X X . . . ",
    ". . . . . X X . X X . X X . . . ",
    ". . . . . X X . X X . X X . . . ",
    ". . . X X X X X X X X X X . . . ",
    ". . . . . . . . . . . . . . . . ",
    ". . . . . . . . . . . . . . . . ",
    "UX. . . . . . . . . . . . . . UX"
};

class wxPlDemoFrame : public wxPLplotwindow<wxFrame>
{
private:
    virtual void OnLocate( const PLGraphicsIn &graphicsIn );
};

void wxPlDemoFrame::OnLocate( const PLGraphicsIn &graphicsIn )
{
    if ( graphicsIn.button == 0 )
        return;         //Do nothing for motion, only respond to clicks

    wxString message;

    if ( ( graphicsIn.state & PL_MASK_SHIFT ) != 0 )
        message << "Shift-";
    if ( ( graphicsIn.state & PL_MASK_CAPS ) != 0 )
        message << "Caps Lock-";
    if ( ( graphicsIn.state & PL_MASK_CONTROL ) != 0 )
        message << "Ctrl-";
    if ( ( graphicsIn.state & PL_MASK_ALT ) != 0 )
        message << "Alt-";
    if ( ( graphicsIn.state & PL_MASK_NUM ) != 0 )
        message << "Num Lock-";
    if ( ( graphicsIn.state & PL_MASK_ALTGR ) != 0 )
        message << "Alt Gr-";
    if ( ( graphicsIn.state & PL_MASK_WIN ) != 0 )
        message << "Win-";
    if ( ( graphicsIn.state & PL_MASK_SCROLL ) != 0 )
        message << "Scroll Lock-";

    if ( graphicsIn.button == 1 )
        message << "Left click.\n";
    else if ( graphicsIn.button == 2 )
        message << "Middle click.\n";
    else if ( graphicsIn.button == 3 )
        message << "Right click.\n";
    message << "Pixels: x = " << graphicsIn.pX << " y = " << graphicsIn.pY << 
".\n";
    if ( graphicsIn.subwindow >= 0 )
    {
        message << "World: x = " << graphicsIn.wX << " y = " << graphicsIn.wY 
<< ".\n";
        message << "Window = " << graphicsIn.subwindow << ".\n";
    }
    else
    {
        message << "Point is not in a Window.\n";
    }
    wxMessageBox( message, "Mouse capture demo" );
}

template< class WXWINDOW >
void Plot( wxPLplotwindow<WXWINDOW> *plotwindow );

class MyApp : public wxApp
{
public:
    virtual bool OnInit();
};

IMPLEMENT_APP( MyApp )

//! This method is called right at the beginning and opens a frame for us.
//
bool MyApp::OnInit()
{
#ifdef __WXMAC__
    // this hack enables to have a GUI on Mac OSX even if the
    // program was called from the command line (and isn't a bundle)
    ProcessSerialNumber psn;

    GetCurrentProcess( &psn );
    CPSEnableForegroundOperation( &psn );
    SetFrontProcess( &psn );
#endif

    //There is only a default constructor for the wxPLplotwindow<> class
    //so we do two stage creation - first use default constructor, then
    //call Create.
    wxPLplotwindow<wxFrame> *frame = new wxPlDemoFrame();
    frame->Create( NULL, wxID_ANY, wxT( "wxPLplotDemo" ));
    PLPLOT_wxLogDebug("frame->Create");
    //Now we can set up our frame and do the plotting
    frame->SetIcon( wxIcon( graph ) );
    frame->Show();
    Plot( frame );

    //note that all the code above starting from the Create() call could
    //instead go in the wxPlDemoFrame constructor should we wish. It is
    //entirely the user's choice.

    return true;
}

template< class WXWINDOW >
void Plot( wxPLplotwindow<WXWINDOW> *plotwindow )
{
  if (!plotwindow->IsReady())
  {
    wxMessageBox(wxT("Somehow we attempted to plot before the wxPLplotwindow 
was ready. The plot will not be drawn."));
    return;
  }
  wxPLplotstream* pls = plotwindow->GetStream();
  PLPLOT_wxLogDebug("Plot()");
    assert(pls);

    const size_t  np = 500;
    PLFLT         x[np], y[np];
    PLFLT         xmin, xmax;
    PLFLT         ymin = 1e30, ymax = 1e-30;

    xmin = -2.0;
    xmax = 10.0;
    for ( size_t i = 0; i < np; i++ )
    {
        x[i] = ( xmax - xmin ) * i / np + xmin;
        y[i] = 1.0;
        if ( x[i] != 0.0 )
            y[i] = sin( x[i] ) / x[i];
        ymin = MIN( ymin, y[i] );
        ymax = MAX( ymax, y[i] );
    }

    pls->adv( 0 );
    pls->col0( 1 );
    pls->env( xmin, xmax, ymin, ymax, 0, 0 );
    pls->col0( 2 );
    pls->lab( "x", "y", "sin(x)/x" );

    pls->col0( 3 );
    pls->width( 2 );
    pls->line( np, x, y );

    plotwindow->RenewPlot();
}

//
//class MyPlotwindow : public wxPLplotwindow
//{
//public:
//    MyPlotwindow( wxFrame* frame, wxWindow* parent, wxWindowID id = -1, const 
wxPoint& pos = wxDefaultPosition,
//                  const wxSize& size = wxDefaultSize, long style = 0,
//                  int pl_style = wxPLPLOT_NONE );
//
//    void OnChar( wxKeyEvent& event );
//
//private:
//    wxFrame* mframe;
//};
//
//
//// Define a new frame type: this is going to be our main frame
//class MyFrame : public wxFrame
//{
//public:
//    MyFrame( const wxString& title );
//    void Plot();
//
//private:
//    void OnQuit( wxCommandEvent& event );
//    void OnAbout( wxCommandEvent& event );
//    void OnBackgroundColor( wxCommandEvent& event );
//
//private:
//    MyPlotwindow* plotwindow;
//    bool        bgcolor;
//    int         m_backend;
//
//    DECLARE_EVENT_TABLE()
//};
//
//
//--------------------------------------------------------------------------
//// constants
//--------------------------------------------------------------------------
//enum { wxPLplotDemo_Quit    = wxID_EXIT, wxPLplotDemo_About = wxID_ABOUT,
//       wxPLplotDemo_BGColor = 10000 };
//
//--------------------------------------------------------------------------
//// event tables and other macros for wxWidgets
//--------------------------------------------------------------------------
//BEGIN_EVENT_TABLE( MyFrame, wxFrame )
//EVT_MENU( wxPLplotDemo_Quit, MyFrame::OnQuit )
//EVT_MENU( wxPLplotDemo_About, MyFrame::OnAbout )
//EVT_MENU( wxPLplotDemo_BGColor, MyFrame::OnBackgroundColor )
//END_EVENT_TABLE()
//
//
//--------------------------------------------------------------------------
//// implementation
//--------------------------------------------------------------------------
//
//
//
//MyPlotwindow::MyPlotwindow( wxFrame* frame, wxWindow* parent, wxWindowID id, 
const wxPoint& pos,
//                            const wxSize& size, long style, int pl_style ) :
//    wxPLplotwindow( parent, id, pos, size, style, pl_style )
//{
//    mframe = frame;
//}
//
//
//void MyPlotwindow::OnChar( wxKeyEvent& event )
//{
//    int keycode = event.GetKeyCode();
//
//    if ( keycode == WXK_RETURN ||
//         keycode == WXK_SPACE ||
//         keycode == WXK_RIGHT ||
//         keycode == WXK_ESCAPE )
//        mframe->Close( true );
//    else
//        event.Skip();
//}
//
//
////! Constructor of our custom frame, where the Menu is created and a
////  a wxPLplotwindow is inserted into the frame. We plot some easy functions
////  just to show how it works. wxPLplotwindow takes care of all the setup
////  for the use of PLplot library.
////
//MyFrame::MyFrame( const wxString& title ) : wxFrame( NULL, wxID_ANY, title )
//{
//    bgcolor = false;
//
//    // add menu
//    wxMenu *fileMenu = new wxMenu;
//    fileMenu->Append( wxPLplotDemo_BGColor, _T( "&Change background 
color...\tAlt-C" ), _T( "Change background color" ) );
//    fileMenu->Append( wxPLplotDemo_About, _T( "&About...\tF1" ), _T( "Show 
about dialog" ) );
//    fileMenu->Append( wxPLplotDemo_Quit, _T( "E&xit\tAlt-X" ), _T( "Quit this 
program" ) );
//
//    wxMenuBar *menuBar = new wxMenuBar();
//    menuBar->Append( fileMenu, _T( "&File" ) );
//    SetMenuBar( menuBar );
//    SetIcon( wxIcon( graph ) );
//
//    // add the wxPLplot
//    wxPanel   * panel = new wxPanel( this );
//    wxBoxSizer* box   = new wxBoxSizer( wxVERTICAL );
//    plotwindow = new MyPlotwindow( this, panel, -1, wxDefaultPosition, 
wxDefaultSize, wxWANTS_CHARS,
//#if wxUSE_GRAPHICS_CONTEXT
//        wxPLPLOT_BACKEND_GC | wxPLPLOT_DRAW_TEXT );
//#else
//        wxPLPLOT_BACKEND_AGG | wxPLPLOT_DRAW_TEXT );
//#endif
//    plotwindow->Connect( wxEVT_CHAR, wxKeyEventHandler( MyPlotwindow::OnChar 
) );
//    box->Add( plotwindow, 1, wxALL | wxEXPAND, 0 );
//    panel->SetSizer( box );
//    SetSize( 640, 500 );      // set frame size
//    SetSizeHints( 220, 150 ); // set minimum frame size
//
//    wxString m_title = title;
//    switch ( plotwindow->getBackend() )
//    {
//    case wxPLPLOT_BACKEND_DC:
//        m_title += wxT( " (basic)" );
//        break;
//    case wxPLPLOT_BACKEND_GC:
//        m_title += wxT( " (wxGC)" );
//        break;
//    case wxPLPLOT_BACKEND_AGG:
//        m_title += wxT( " (AGG)" );
//        break;
//    default:
//        break;
//    }
//    SetTitle( m_title );
//
//    Plot();
//}
//
//void MyFrame::Plot()
//{
//    wxPLplotstream* pls = plotwindow->GetStream();
//
//    const size_t  np = 500;
//    PLFLT         x[np], y[np];
//    PLFLT         xmin, xmax;
//    PLFLT         ymin = 1e30, ymax = 1e-30;
//
//    xmin = -2.0;
//    xmax = 10.0;
//    for ( size_t i = 0; i < np; i++ )
//    {
//        x[i] = ( xmax - xmin ) * i / np + xmin;
//        y[i] = 1.0;
//        if ( x[i] != 0.0 )
//            y[i] = sin( x[i] ) / x[i];
//        ymin = MIN( ymin, y[i] );
//        ymax = MAX( ymax, y[i] );
//    }
//
//    pls->adv( 0 );
//    if ( bgcolor )
//    {
//        pls->scol0( 0, 255, 255, 255 );
//        pls->scol0( 15, 0, 0, 0 );
//    }
//    else
//    {
//        pls->scol0( 15, 255, 255, 255 );
//        pls->scol0( 0, 0, 0, 0 );
//    }
//    pls->col0( 1 );
//    pls->env( xmin, xmax, ymin, ymax, 0, 0 );
//    pls->col0( 2 );
//    pls->lab( "x", "y", "sin(x)/x" );
//
//    pls->col0( 3 );
//    pls->width( 2 );
//    pls->line( np, x, y );
//
//    plotwindow->RenewPlot();
//}
//
//
//void MyFrame::OnQuit( wxCommandEvent& WXUNUSED( event ) )
//{
//    Close( true );
//}
//
//
//void MyFrame::OnBackgroundColor( wxCommandEvent& WXUNUSED( event ) )
//{
//    bgcolor = !bgcolor;
//    Plot();
//}
//
//
////! Show information if Menu entry About was choosen.
////
//void MyFrame::OnAbout( wxCommandEvent& WXUNUSED( event ) )
//{
//    wxMessageBox( _T( "This is the About dialog of the wxPLplot demo.\n" ), 
_T( "About wxPLplot" ),
//        wxOK | wxICON_INFORMATION, this );
//}
// Copyright (C) 2015  Phil Rosenberg
// Copyright (C) 2005  Werner Smekal
//
// This file is part of PLplot.
//
// PLplot is free software; you can redistribute it and/or modify
// it under the terms of the GNU Library General Public License as published
// by the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// PLplot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public License
// along with PLplot; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//

#if !defined ( WXPLPLOTWINDOW_H__INCLUDED_ )
#define WXPLPLOTWINDOW_H__INCLUDED_

#include "plplot.h"
#include "wxPLplotstream.h"
#include <wx/window.h>
#include <wx/dcmemory.h>
#include <wx/dcclient.h>
#include <wx/dcgraph.h>
#include <wx/dcbuffer.h>

// A plplot wxWindow template. To create an actual plplot wxWindow use
// the type of wxWindow you wish to inherit from at the template parameter
// For example to create a plplot wxFrame create a wxPLplotwindow<wxFrame>
// then call the base wxWindow's Create method to initialise.
template <class WXWINDOW>
class wxPLplotwindow : public WXWINDOW
{
public:
    wxPLplotwindow( bool useGraphicsContext = true, wxSize clientSize = 
wxDefaultSize ); //!< Constructor.
    virtual ~wxPLplotwindow( void );                                            
         //!< Destructor.

    void RenewPlot( void );                                                     
         //!< Redo plot.
    bool SavePlot( const wxString& driver, const wxString& filename );          
         //!< Save plot using a different driver.
    wxPLplotstream* GetStream()  { return m_created ? &m_stream : NULL; }       
         //!< Get pointer to wxPLplotstream of this widget.
    void setUseGraphicsContext( bool useGraphicsContext );
    void setCanvasColour( const wxColour &colour );
    bool IsReady() { return GetStream() != NULL; }

    bool Create(wxWindow *parent,
      wxWindowID id,
      const wxString& title,
      const wxPoint& pos = wxDefaultPosition,
      const wxSize& size = wxDefaultSize,
      long style = wxDEFAULT_FRAME_STYLE,
      const wxString& name = wxFrameNameStr);

protected:
    void CreateStream();
    virtual void OnPaint( wxPaintEvent& event );         //!< Paint event
    virtual void OnSize( wxSizeEvent & event );          //!< Size event
    virtual void OnErase( wxEraseEvent &event );         //!< Background erase 
event
    virtual void OnCreate( wxWindowCreateEvent &event ); //!< Window created 
event
    void OnMouse( wxMouseEvent &event );                 //!< Mouse events
    wxPLplotstream m_stream;                             //!< The 
wxPLplotstream which belongs to this plot widget
    bool           m_created;                            //!< Flag to indicate 
the window has been Created

private:
    bool     m_useGraphicsContext;                       //!< Flag to indicate 
whether we should use a wxGCDC
    wxBitmap m_bitmap;
    // The memory dc and wrapping gc dc for drawing. Note we
    //use pointers and reallocate them whenever the bitmap is
    //resized because reusing either of these causes problems
    //for rendering on a wxGCDC - at least on Windows.
    wxMemoryDC *m_memoryDc;
    wxSize     m_initialSize;
#ifdef wxUSE_GRAPHICS_CONTEXT
    wxGCDC     *m_gcDc;
#endif
    wxColour   m_canvasColour;
    virtual void OnLocate( const PLGraphicsIn &graphicsIn ){}
};


//! Constructor initialises variables, creates the wxStream and connects
// methods with events. The WXWINDOW default constructor is used.
//
template<class WXWINDOW>
wxPLplotwindow<WXWINDOW>::wxPLplotwindow( bool useGraphicsContext, wxSize 
clientSize )
    : m_created( false ), m_initialSize( clientSize )

{
    PLPLOT_wxLogDebug("wxPLplotwindow::wxPLplotwindow");
    m_memoryDc = NULL;
#ifdef wxUSE_GRAPHICS_CONTEXT
    m_gcDc = NULL;
#endif
    setUseGraphicsContext( useGraphicsContext );
    m_canvasColour = *wxBLACK;

    //We use connect instead of Bind for compatiblity with wxWidgets 2.8
    //but should move to bind in the future.
    WXWINDOW::Connect( wxEVT_SIZE, wxSizeEventHandler( 
wxPLplotwindow<WXWINDOW>::OnSize ) );
    WXWINDOW::Connect( wxEVT_PAINT, wxPaintEventHandler( 
wxPLplotwindow<WXWINDOW>::OnPaint ) );
    WXWINDOW::Connect( wxEVT_ERASE_BACKGROUND, wxEraseEventHandler( 
wxPLplotwindow<WXWINDOW>::OnErase ) );
    WXWINDOW::Connect( wxEVT_CREATE, wxWindowCreateEventHandler( 
wxPLplotwindow<WXWINDOW>::OnCreate ) );
    WXWINDOW::Connect( wxEVT_MOTION, wxMouseEventHandler( 
wxPLplotwindow<WXWINDOW>::OnMouse ) );
    WXWINDOW::Connect( wxEVT_LEFT_UP, wxMouseEventHandler( 
wxPLplotwindow<WXWINDOW>::OnMouse ) );
    WXWINDOW::Connect( wxEVT_MIDDLE_UP, wxMouseEventHandler( 
wxPLplotwindow<WXWINDOW>::OnMouse ) );
    WXWINDOW::Connect( wxEVT_RIGHT_UP, wxMouseEventHandler( 
wxPLplotwindow<WXWINDOW>::OnMouse ) );
}


//! Destructor - delete the dc and gcdc if needed.
//
template<class WXWINDOW>
wxPLplotwindow<WXWINDOW>::~wxPLplotwindow( void )
{
    if ( m_memoryDc )
        delete m_memoryDc;
    if ( m_gcDc )
        delete m_gcDc;
}

template<class WXWINDOW>
bool wxPLplotwindow<WXWINDOW>::Create(wxWindow *parent, wxWindowID id, const 
wxString& title, const wxPoint& pos, const wxSize& size, long style, const 
wxString& name)
{
  PLPLOT_wxLogDebug("wxPLplotwindow::Create()");
  if (!WXWINDOW::Create(parent, id, title, pos, size, style, name))
    return false;
  CreateStream();
  return true;
}


template<class WXWINDOW>
void wxPLplotwindow<WXWINDOW>::CreateStream(void)
{
  PLPLOT_wxLogDebug("wxPLplotwindow::CreateStream()");
  if (!m_created)
  {
    //set the client size if requested
    if (m_initialSize != wxDefaultSize)
      WXWINDOW::SetClientSize(m_initialSize);
    //create the stream
    int width = WXWINDOW::GetClientSize().GetWidth();
    int height = WXWINDOW::GetClientSize().GetHeight();
    m_bitmap.Create(width, height);
    if (m_memoryDc)
      delete m_memoryDc;
    m_memoryDc = new wxMemoryDC;
    m_memoryDc->SelectObject(m_bitmap);
    wxDC * drawDc = m_memoryDc;
#ifdef wxUSE_GRAPHICS_CONTEXT
    if (m_useGraphicsContext)
    {
      if (m_gcDc)
        delete m_gcDc;
      m_gcDc = new wxGCDC(*m_memoryDc);
      drawDc = m_gcDc;
    }
#endif
    if (!m_stream.IsValid())
      m_stream.Create(drawDc, width, height, wxPLPLOT_DRAW_TEXT);
    else
      m_stream.SetDC(drawDc);
    drawDc->SetBackground(wxBrush(m_canvasColour));
    drawDc->Clear();

    m_created = true;
    RenewPlot();
  }
}

//! In the OnPaint Method we check if the Windows was resized (will be moved to 
OnSize() sometimes
//  later), we also implement our own double buffering here (since the PLplot 
wxWidgets driver draws
//  into a wxMemoryDC)
//
template<class WXWINDOW>
void wxPLplotwindow<WXWINDOW>::OnPaint( wxPaintEvent &WXUNUSED( event ) )
{
    //Really this should be in the constructor, but it caused a segfault
    //on at least one system (CentOS with intel compiler and wxWidgets 2.8.12).
    //Moving it here after WXWINDOW::Create has been called stops this and
    //the call does nothing if the style is the same as previous calls so
    //should be safe to call here.
    //WXWINDOW::SetBackgroundStyle( wxBG_STYLE_CUSTOM );


    //wxAutoBufferedPaintDC dc( (WXWINDOW*)this );
    int       width  = WXWINDOW::GetClientSize().GetWidth();
    int       height = WXWINDOW::GetClientSize().GetHeight();

    wxPaintDC paintDc( this );

    //resize the plot if needed
    bool needResize = width != m_bitmap.GetWidth() || height != 
m_bitmap.GetHeight();
    if ( needResize )
    {
        m_bitmap.Create( width, height, 32 );
        if ( m_memoryDc )
            delete m_memoryDc;
        m_memoryDc = new wxMemoryDC;
        m_memoryDc->SelectObject( m_bitmap );
        wxDC *drawDc = m_memoryDc;
#ifdef wxUSE_GRAPHICS_CONTEXT
        if ( m_useGraphicsContext )
        {
            if ( m_gcDc )
                delete m_gcDc;
            m_gcDc = new wxGCDC( *m_memoryDc );
            drawDc = m_gcDc;
        }
#endif
        if( IsReady() )
            m_stream.SetDC( drawDc );
        drawDc->SetBackground( wxBrush( m_canvasColour ) );
        drawDc->Clear();
        if( IsReady() )
            m_stream.SetSize( width, height );
    }

    paintDc.Blit( 0, 0, width, height, m_memoryDc, 0, 0 );
}

//! This is called when the plot is resized
//
template<class WXWINDOW>
void wxPLplotwindow<WXWINDOW>::OnSize( wxSizeEvent& WXUNUSED( event ) )
{
    //Invalidate the whole window so it is all redrawn, otherwise only
    //newly exposed parts of the window get redrawn
    RenewPlot();
}

//! This is called before each paint event
//
template<class WXWINDOW>
void wxPLplotwindow<WXWINDOW>::OnErase( wxEraseEvent& WXUNUSED( event ) )
{
    //Do nothing. This stops screen flicker.
}

//! This is called when the widow is created i.e. after WXWINDOW::Create
//  has been called. We note that this has been called to avoid attempting
//  to redraw a plot on a window that hasn't been created yet.
template<class WXWINDOW>
void wxPLplotwindow<WXWINDOW>::OnCreate( wxWindowCreateEvent &event )
{
    PLPLOT_wxLogDebug("wxPLplotwindow::OnCreate");
    CreateStream();
}

//Capture Mouse events and pass the
template<class WXWINDOW>
void wxPLplotwindow<WXWINDOW>::OnMouse( wxMouseEvent &event )
{
    PLGraphicsIn graphicsIn;
    wxPoint      cursorPosition = event.GetPosition();
    wxSize       clientSize     = WXWINDOW::GetClientSize();

    graphicsIn.pX        = cursorPosition.x;
    graphicsIn.pY        = cursorPosition.y;
    graphicsIn.dX        = PLFLT( cursorPosition.x + 0.5 ) / PLFLT( 
clientSize.GetWidth() );
    graphicsIn.dY        = 1.0 - PLFLT( cursorPosition.y + 0.5 ) / PLFLT( 
clientSize.GetHeight() );
    graphicsIn.keysym    = 0x20;
    graphicsIn.state     = 0;
    graphicsIn.subwindow = -1;
    graphicsIn.type      = 0;
    graphicsIn.string[0] = '\0';
    if ( event.LeftUp() )
    {
        graphicsIn.button = 1;
        graphicsIn.state |= PL_MASK_BUTTON1;
    }
    else if ( event.MiddleUp() )
    {
        graphicsIn.button = 2;
        graphicsIn.state |= PL_MASK_BUTTON2;
    }
    else if ( event.RightUp() )
    {
        graphicsIn.button = 3;
        graphicsIn.state |= PL_MASK_BUTTON3;
    }
    else if ( event.Aux1Up() )
    {
        graphicsIn.button = 4;
        graphicsIn.state |= PL_MASK_BUTTON4;
    }
    else if ( event.Aux2Up() )
    {
        graphicsIn.button = 5;
        graphicsIn.state |= PL_MASK_BUTTON5;
    }
    else
    {
        //If we get here we have just captured motion
        //not a click
        graphicsIn.button = 0;
        graphicsIn.state  = 0;
        graphicsIn.keysym = 0;
    }

    if ( wxGetKeyState( WXK_SHIFT ) )
        graphicsIn.state |= PL_MASK_SHIFT;
    if ( wxGetKeyState( WXK_CAPITAL ) )
        graphicsIn.state |= PL_MASK_CAPS;
    if ( wxGetKeyState( WXK_ALT ) && wxGetKeyState( WXK_CONTROL ) )
        graphicsIn.state |= PL_MASK_ALTGR;
    else if ( wxGetKeyState( WXK_CONTROL ) )
        graphicsIn.state |= PL_MASK_CONTROL;
    else if ( wxGetKeyState( WXK_ALT ) )
        graphicsIn.state |= PL_MASK_ALT;
    if ( wxGetKeyState( WXK_NUMLOCK ) )
        graphicsIn.state |= PL_MASK_NUM;
    if ( wxGetKeyState( WXK_SCROLL ) )
        graphicsIn.state |= PL_MASK_SCROLL;
    //Note I can't find a way to catch the windows key

    if( IsReady() )
        m_stream.translatecursor( &graphicsIn );
    this->OnLocate( graphicsIn );
}

//! Redo the whole plot, only if the window has been Created
//
template<class WXWINDOW>
void wxPLplotwindow<WXWINDOW>::RenewPlot( void )
{
    if ( m_created )
    {
        WXWINDOW::Refresh();
    }
}


//! Save plot.
//
template<class WXWINDOW>
bool wxPLplotwindow<WXWINDOW>::SavePlot( const wxString& devname, const 
wxString& filename )
{
    int  pls, pls_save;
    FILE *sfile;

    if ( ( sfile = fopen( filename.mb_str(), "wb+" ) ) == NULL )
    {
        return false;
    }

    plgstrm( &pls );
    plmkstrm( &pls_save );
    if ( pls_save < 0 )
    {
        fclose( sfile );
        return false;
    }
    plsdev( devname.mb_str() );
    plsfile( sfile );

    plspage( 0., 0., 800, 600, 0, 0 );
    plcpstrm( pls, 0 );
    pladv( 0 );
    plreplot();
    plend1();
    plsstrm( pls );

    return true;
}

//! Set whether we wish to use wxGCDC instead of a wxDC
template<class WXWINDOW>
void wxPLplotwindow<WXWINDOW>::setUseGraphicsContext( bool useGraphicsContext )
{
    wxDC *drawDc;
#ifdef wxUSE_GRAPHICS_CONTEXT
    if ( useGraphicsContext != m_useGraphicsContext )
    {
        m_useGraphicsContext = useGraphicsContext;
        drawDc = m_useGraphicsContext ? (wxDC *) m_gcDc : (wxDC *) m_memoryDc;
    }
#else
    drawDc = &m_memoryDc;
    m_useGraphicsContext = false;
#endif
    if ( IsReady() )
    {
        m_stream.SetDC( drawDc );
        RenewPlot();
    }
}

template<class WXWINDOW>
void wxPLplotwindow<WXWINDOW>::setCanvasColour( const wxColour &colour )
{
    m_canvasColour = colour;
    RenewPlot();
}

#endif // !defined( WXPLPLOTWINDOW_H__INCLUDED_ )
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most 
engaging tech sites, SlashDot.org! http://sdm.link/slashdot
_______________________________________________
Plplot-devel mailing list
Plplot-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/plplot-devel

Reply via email to