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