I'm trying to create my first threaded application with fltk. I have two 
threads: one that produces stuff and the gui thread. For simplicity, the 
producer thread just generates random rectangles and tells the gui thread 
to draw them via Fl::awake(). See code below. 

The problem is I have to put the producer thread to sleep() for a few 
seconds right at the beginning of the thread function, to allow for 
everything else to get going. See makeRectangles() below.

I imagine this is not the proper way to make sure all threads have 
started, so what's the right way? 

Also, the threads.cxx example from fltk-1.1 locks/unlocks in the 
"producer" thread, but that's because it adds rows to the browsers. I'm 
not accessing any fltk widgets, so I don't have to lock, is that correct? 

Finally, there seems to be another way of drawing from a non-gui thread 
in the gui thread, using Fl::add_fd(), as explained here: 

http://www.angelfire.com/linux/tzptech/fltk/fltk-mt.pdf

Is this what Fl::awake() does behind the scenes? 



Thanks. 



//
// g++ -g -Wall -o randRectangle randRectangle.C `fltk-config --ldflags` -
lpthread
//

#include <FL/Fl.H>
#include <FL/Fl_Widget.H>
#include <FL/fl_draw.H>
#include <FL/Fl_Window.H>
#include <FL/fl_ask.H>


#include <iostream>
#include <pthread.h>

using namespace std;



typedef pthread_t Fl_Thread;

static int fl_create_thread(Fl_Thread& t, void *(*f) (void *), void* p) 
{
    return pthread_create((pthread_t*)&t, 0, f, p);
}



struct Color
{
    int red, green, blue;
    Color(int r=0,int g=0,int b=0) : red(r), green(g), blue(b) {};
};


struct Rectangle
{
    Color clr;
    int x,y,w,h;
};



class Canvas : public Fl_Widget
{

public:
    Canvas(int x, int y, int w, int h) : Fl_Widget(x,y,w,h) {}

    void draw()  {
        fl_push_clip(x(), y(), w(), h());
        fl_rectf(0,0,w(),h(),255,255,255);
        fl_pop_clip();
    }

    int handle(int event) {

        switch(event){
        case FL_FOCUS:
            return 1;
        case FL_KEYDOWN:   
            cerr << Fl::event_key() << endl;
            if(Fl::event_key()=='q') exit(0);
            break;
        default:
            return Fl_Widget::handle(event);
        }

        draw();         // Draw on each event received. 
        return 1;
    };

};


// Callback for Fl::awake()
void drawRectangle(void * data)
{
    Rectangle * X=(Rectangle*) data;
    fl_rectf(X->x,X->y,X->w,X->h,
             X->clr.red,X->clr.green,X->clr.blue);
}


// Worker thread function: generate rectangles at random positions.
void * makeRectangles(void * p)
{
    Canvas * theCanvas=(Canvas*) p;
    Rectangle X;

    X.w=5;
    X.h=5;
    X.clr.red=0;
    X.clr.green=0;
    X.clr.blue=255;

    size_t nSleep=2;
    cerr << "Waiting " << nSleep << " seconds" << endl;
    sleep(nSleep);
    for(size_t i=0; i<1000000; i++){
        cout << i << endl;

        // Choose x,y randomly:
        X.x=rand()%theCanvas->w();
        X.y=rand()%theCanvas->h();

        // and tell gui thread to draw.
        Fl::awake(drawRectangle, &X);
        // usleep(100000);
    }

    return 0;
}



int main()
{

    Fl_Window window(400, 400, 0);
    Canvas theCanvas(0,0,400,400);   

    window.end();
    window.show();

    Fl_Thread producerThread;

    Fl::lock();
    fl_create_thread(producerThread, makeRectangles, &theCanvas);

    Fl::run();
}



_______________________________________________
fltk mailing list
[email protected]
http://lists.easysw.com/mailman/listinfo/fltk

Reply via email to