Just wanted to update my post from yesterday with a small change. I found out later that when using the cairo window within a parent fltk::Window along with other widgets (in my case the plplot cairo window is part of a fltk::TabGroup), the call that passes the fltk cairo context to the plplot library for initialization ( mPLS->cmd(PLESC_DEVINIT, fltk::cr) ) will affect the layout of the rest of the widgets in the fltk application. So to fix that the cmd call must be wrapped in cairo_save/restore calls. This unexpectedly inverted the plot when it was drawn, so that the chart was drawn reflected about its x axis. To correct this behavior inside CairoWindow::draw() apply a translation and a scaling to the cairo context before making any plplot calls. See below.

 

 

-Marco

 

// This example was compiled using the following commands:

//

// c++ -g3 -O0 -I/devel/UFM/fltk-2.0.x-alpha-r9204 -I/usr/include/freetype2 -I/usr/include/cairo -I/usr/include/freetype2 -I/usr/include/libpng12 -Wno-non-virtual-dtor `PKG_CONFIG_PATH=/usr/local/depot/plplot-5.9.7/plplot-5.9.7/lib/pkgconfig pkg-config --cflags plplotd plplotd-c++` -c -o cairo.o cairo.cxx

// c++ -g3 -O0 -Wl,-rpath -Wl,/usr/local/depot/plplot-5.9.7/plplot-5.9.7/lib:/usr/local/depot/qt-4.7.4/qt-4.7.4/lib:/usr/local/plplot-5.9.7/lib -o cairo cairo.o -L/devel/UFM/fltk-2.0.x-alpha-r9204/lib -lfltk2_gl -lGLU -lGL -lfltk2 -lX11 -lXi -lXinerama -lXft -lpthread -lm -lXext -lcairo -lsupc++ `PKG_CONFIG_PATH=/usr/local/depot/plplot-5.9.7/plplot-5.9.7/lib/pkgconfig pkg-config --libs plplotd plplotd-c++ cairo`

//

// Adjust the path to your plplot and fltk libraries as necessary. Also, fltk was configured with –enable-cairo=yes

 

 

 

#include <config.h>

#include <fltk/run.h>

//#include <fltk/x.h>

#include <fltk/fltk_cairo.h>

#include <fltk/DoubleBufferWindow.h>

#include <fltk/draw.h>

#include <fltk/math.h>

 

#include <fltk/Group.h>

#include <fltk/TabGroup.h>

 

#include <iostream>

#include <plplot.h>

#include <plstream.h>

 

using namespace fltk;

 

int nsteps = 1000;

 

class CairoWindow : public Window

{

   public:

 

      CairoWindow(int argc, const char *argv[])

         : Window(720,540), firstPass(true), ArgC(argc), ArgV(argv)

      {

         n = 0;

         resizable(this);                         // comment this out for fixed-size

         color(fltk::WHITE);                      // desired background color

     }

 

      CairoWindow(int x, int y, int w, int h, int argc, const char *argv[])

         : Window(x, y, w, h), firstPass(true), ArgC(argc), ArgV(argv)

      {

         n = 0;

         resizable(this);                         // comment this out for fixed-size

         color(fltk::WHITE);                      // desired background color

      }

 

      bool firstPass;

      int ArgC;

      const char **ArgV;

 

      void Init()

      {

         // Make sure the cairo context exists before attempting

         // to pass the pointer to plplot.

         if(fltk::cr != NULL)

         {

            // Perform the plplot initialization required by your

            // task.

            pls = new plstream();

            pls->parseopts(&ArgC, ArgV, PL_PARSE_FULL);

 

            ymin = -0.1;

            ymax = 0.1;

           

            tmin  = 0.;

            tmax  = 110.;

            tjump = 0.3;

 

            colbox     = 1;

            collab     = 3;

            styline[0] = colline[0] = 2;      // pens color and line style

            styline[1] = colline[1] = 3;

            styline[2] = colline[2] = 4;

            styline[3] = colline[3] = 5;

 

            legline[0] = "sum";                       // pens legend

            legline[1] = "sin";

            legline[2] = "sin*noi";

            legline[3] = "sin+noi";

 

            xlab = 0.; ylab = 0.25;   // legend position

 

            autoy = true;             // autoscale y

            acc   = true;

 

            pls->sdev("extcairo");

            pls->init();

 

            // Need to save the cairo context or else the rest of

            // the fltk drawing calls get out of whack...

            cairo_save(cr);

 

            pls->cmd(PLESC_DEVINIT, fltk::cr);

 

            cairo_restore(cr);

 

            pls->adv(0);

            pls->vsta();

 

            pls->sError(&pl_errcode, errmsg);

 

            pls->stripc( &id1, "bcnst", "bcnstv",

                          tmin, tmax, tjump, ymin, ymax,

                          xlab, ylab,

                          autoy, acc,

                          colbox, collab,

                          colline, styline, legline,

                          "t", "", "Strip chart demo" );

 

            if ( pl_errcode )

            {

               std::cout << errmsg << std::endl;

                delete pls;

                exit( 1 );

            }

 

            pls->sError(NULL, NULL);

 

            autoy = false; // autoscale y

            acc   = true;  // accumulate/

 

            y1 = y2 = y3 = y4 = 0.0;

            dt = 0.1;

 

            // Only after successfully calling this we can flip the

            // flag to false.

            firstPass = false;

         }

      }

 

      static void TimeOutCB(void *data)

      {

         CairoWindow *w = (CairoWindow *) data;

         // We check if we should run the real-time data

         // capture and computation, otherwise do not

         // reset the timeout and "stop" the real-time.

         if(w->n < nsteps)

         {

            // If this is the first time we called in here

            // then initialize the class and the plplot interface.

            if(w->firstPass == true)

            {

               w->Init();

            }

            else

            {

               // Otherwise, perform the real-time computation

               // and request a re-draw of the screen from the

               // fltk main loop.

               w->Compute();

               fltk::redraw();

            }

            fltk::repeat_timeout(0.01, w->TimeOutCB, data);

         }

      }

 

      void Compute()

      {

         // Compute values for each time-step

         t     = (double) n * dt;

        //noise = (1.0 * (rand() / (RAND_MAX + 1.0))) - 0.5;

        noise = pls->randd() - 0.5;

        y1    = y1 + noise;

        y2    = sin( t * M_PI / 18. );

        y3    = y2 * noise;

        y4    = y2 + noise / 3.;

 

        ++n;

      }

 

      void draw()

      {

         // So we wait to see if this is the first time we called into here

         // and if it is, then we set timeout. Now go to TimeOutCB to follow

         // the sequence of events.

         if(firstPass == false)

         {

            cairo_save(cr);

 

            // For a reason I don't understand, adding the

            // cairo_save/restore calls in Init() when passing

            // the cairo context in pls->cmd(PLESC_DEVINIT, fltk::cr)

            // causes the plot to draw up-side-down, so we reflect

            // it back to right-side-up.

            cairo_translate(cr, 0.0, h());

            cairo_scale(cr, 1.0, -1.0);

 

            if ( n % 2 )

               pls->stripa( id1, 0, t, y1 );

            if ( n % 3 )

                pls->stripa( id1, 1, t, y2 );

            if ( n % 4 )

                pls->stripa( id1, 2, t, y3 );

            if ( n % 5 )

                pls->stripa( id1, 3, t, y4 );

 

            cairo_restore(cr);

         }

         else

         {

            fltk::add_timeout(0.01, this->TimeOutCB, this);

         }

      }

 

      static PLINT pl_errcode;

      static char  errmsg[160];

 

      PLINT n;

   private:

      plstream *pls;

 

      PLINT      id1;

      bool       autoy, acc;

      PLFLT      y1, y2, y3, y4, ymin, ymax, xlab, ylab;

      PLFLT      t, tmin, tmax, tjump, dt, noise;

      PLINT      colbox, collab, colline[4], styline[4];

      const char *legline[4];

};

 

PLINT CairoWindow::pl_errcode   = 0;

char  CairoWindow:: errmsg[160] = "";

 

int main(int argc, char** argv)

{

   fltk::Window *w = new fltk::Window(720, 540);

   w->begin();

   {

      fltk::TabGroup *t = new fltk::TabGroup(0, 0, w->w(), w->h());

      t->begin();

      {

         //fltk::Group *g = new fltk::Group(0, 0, t->w(), t->h() - 24, " Plot ");

         //g->box(fltk::EMBOSSED_BOX);

         //g->begin();

         {

            const char *constArgv[argc];

            for(int i = 0; i < argc; ++i)

            {

               constArgv[i] = "\0"; //argv[i];

            }

 

            // Create the window

            //CairoWindow *plotWin = new CairoWindow(0, 0, g->w(), g->h(), argc, constArgv);

            CairoWindow *plotWin = new CairoWindow(0, 0, t->w(), t->h() - 24, argc, constArgv);

 

         }

         //g->end();

      }

      t->end();

   }

   w->end();

   w->show();

 

   // The plplot library expects argv as const pointers

   // but fltk does not, so we create a const copy to pass

   // to plplot.

   //const char *constArgv[argc];

   //for(int i = 0; i < argc; ++i)

   //{

   //   constArgv[i] = argv[i];

   //}

 

   //// Create the window

   //CairoWindow window(argc, constArgv);

   //window.show(argc,argv);

 

   // In fltk, ONLY after calling the main loop in run() will the

   // fltk cairo context be created and the surface initialized.

   // Trying to operate on the fltk cairo context before calling run()

   // will result in the use of a null pointer. From here go to draw() call

   // in CairoWindow() for more comments on these steps.

   return fltk::run();

}