All,

Earlier in the week, I posted asking about issues I was having with  
Cairo rendering in a fltk-1.1.9 / fltk-1.3 window, that only occurred  
under OSX. On linux and win32 the same code seemed to run just fine,  
but on OSX the Cairo scene was rendered upside down...

Well, following some investigation, I now understand what triggers  
that effect, so I thought I'd post here for the benefit of others.

The key to this turns out to be *when* I modify fltk's clip region.
If I modify the clip region *before* I obtain a Cairo context for the  
window, all is well.
But if I obtain the Cairo context, *then* modify the clip region, all  
the Cairo drawing is inverted and offset.

Perhaps it is obvious to others that this could happen, but it was  
not obvious to me, so I thought I'd better flag it up.

Here's a demo program that shows the effect - on linux, it Just  
Works, but on OSX 10.4.11, toggling the check-box will flip the image  
in the box.

There's nothing too complex in the codem but you will need to link  
fltk, cairo and pixman... I'm using...

-lfltk -lcairo -lpng12 -lz -lpixman-1 -lpthread -framework Carbon - 
framework ApplicationServices

--------------------------
#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Box.H>
#include <FL/x.H>
#include <FL/fl_draw.H>
#include <FL/Fl_Check_Button.H>
#include <FL/Fl_Button.H>

#include <cairo.h>

#ifdef WIN32
#  include <cairo-win32.h>
#elif defined (__APPLE__)
#  include <cairo-quartz.h>
#else
#  include <cairo-xlib.h>
#endif

#ifdef WIN_BASE
#  warning Fl_Double_Window base
#  define BOX Fl_Double_Window
#else
#  define BOX Fl_Box
#endif

Fl_Check_Button *fail_bt=(Fl_Check_Button *)0;
/*************************************************************/
class test_box : public BOX {
        void draw(void); // draw method
        cairo_surface_t *surface;
        cairo_t *cairo_context;
        void set_cairo_cxt(int wo, int ho);
public:
        // constructor
        test_box(int x, int y, int w, int h) : BOX(x,y,w,h) {
                surface = NULL; cairo_context = NULL;}
};
/*************************************************************/
void test_box::set_cairo_cxt(int wo, int ho) {
#ifdef WIN32
#warning win32 mode
        /* Get a Cairo surface for the current DC */
        HDC dc = fl_gc;         /* Exported by fltk */
        surface = cairo_win32_surface_create(dc);
#elif defined (__APPLE__)
#warning Apple Quartz mode
        /* Get a Cairo surface for the current CG context */
        CGContext *ctx = fl_gc;
        surface = cairo_quartz_surface_create_for_cg_context(ctx, wo, ho);
#else
#warning X windows mode
        /* Get a Cairo surface for the current display */
        surface = cairo_xlib_surface_create(fl_display, fl_window, fl_visual- 
 >visual, wo, ho);
#endif
        /* Store the cairo context */
        cairo_context = cairo_create(surface);

        /* All Cairo co-ordinates are shifted by 0.5 pixels to correct anti- 
aliasing */
        cairo_translate(cairo_context, 0.5, 0.5);
}
/*************************************************************/
void test_box::draw(void) {
#ifdef WIN_BASE
        int xo = 0; // origin is (0,0) for Fl_Window
        int yo = 0;
#else
        int xo = x(); // origin is current window position for Fl_Box
        int yo = y();
#endif
        int wo = w();
        int ho = h();
        // setting cairo conext *before* setting clip regions causes problems
        if(fail_bt->value()) {
                set_cairo_cxt(wo, ho);
        }
        // draw the base widget
        fl_push_no_clip(); // remove any clipping region set by the expose  
events...
        fl_push_clip(xo, yo, wo, ho); // reset local clipping

        fl_color(FL_CYAN);
        fl_rectf(xo, yo, wo, ho);
        // setting cairo conext *after* setting clip regions is OK
        if(!fail_bt->value()) {
                set_cairo_cxt(wo, ho);
        }
        // draw a 70% red triangle pointing upwards
        int x1, y1, x2, y2, x3, y3;
        x1 = xo + wo/2; y1 = yo;
        x2 = xo + wo; y2 = yo + ho;
        x3 = xo; y3 = y2;
        cairo_set_source_rgba(cairo_context, 1.0, 0.0, 0.0, 0.7);
        cairo_new_path(cairo_context);
        cairo_move_to(cairo_context, x1, y1);
        cairo_line_to(cairo_context, x2, y2);
        cairo_line_to(cairo_context, x3, y3);
        cairo_line_to(cairo_context, x1, y1);
        cairo_fill(cairo_context);
        // release the cairo context
        cairo_destroy(cairo_context);
        cairo_surface_destroy(surface);
        cairo_context = NULL;

        fl_pop_clip(); // remove the local clip region
        fl_pop_clip(); // remove the "no_clip" region
} // draw method

/*************************************************************/
Fl_Double_Window *main_win=(Fl_Double_Window *)0;
test_box *test=(test_box *)0;
/*************************************************************/
static void cb_Quit(Fl_Button*, void*) {
   main_win->hide();
}
static void cb_fail_bt(Fl_Check_Button*, void*) {
   // force redraw
        test->redraw();
}
/*************************************************************/
int main(int argc, char **argv) {
        main_win = new Fl_Double_Window(500, 500);
        main_win->begin();

        Fl_Button* o = new Fl_Button(430, 460, 60, 30, "Quit");
        o->box(FL_THIN_UP_BOX);
        o->callback((Fl_Callback*)cb_Quit);

        fail_bt = new Fl_Check_Button(10, 460, 90, 25, "OSX fail");
        fail_bt->callback((Fl_Callback*)cb_fail_bt);

        test = new test_box(10, 10, 480, 440);
        test->box(FL_FLAT_BOX);
        main_win->end();
        main_win->resizable(test);
#ifdef WIN_BASE
        main_win->label("Cairo Test (win)");
#else
        main_win->label("Cairo Test (box)");
#endif
        main_win->show(argc, argv);
        test->show();
        test->redraw();
        return Fl::run();
}
/* end of file */

--------------------------
-- 
Ian



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

Reply via email to