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
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