> I made these changes to your original program, and it seemed
> to work for me (comments follow the code). I *only* tested on
> linux.
This is interesting - I was "sure" my example worked on Linux, but testing on the F17 VM I have to hand, it does indeed mess up...
As to why, I *think* the crux is how I am creating cairo_xlib_surface_create(...) here.
Analysis follows, quite possibly flawed!
Note that in Chris's example (very nice, BTW), he derived the cairo_xlib_surface_create() from the main window, and it is sized to fit the main window.
However, in my code I am setting the cairo_xlib_surface_create() based on the dimensions of the derived Fl_Box, but still based on the main window.
So the "origin" of this surface is that of the window, but the width/height is based on the box.
And so the created surface is "too small" or "in the wrong place" for the drawing I want to do, and a nasty mess ensues.
I think Greg's fix works because it forces the created surface to be "big enough" and then it works again. Maybe. Something like that.
I offer an alternate solution below, based on my analysis here, that appears to be working nicely on my F17 VM and on Win7. I do not have a Mac to hand, will test later.
> Note my comment regarding the OSX code,
> a change I didn't make, but might be needed as well.
I think I tested this on OSX and it was OK as-is. But then I *thought* the Linux variant was OK...
Here's the tweaked version of my code, which seems good so far...
--------------------------------------
/* Demo of a simple cairo_box in a group */
#include <FL/Fl.H>
#include <FL/Fl_Group.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Box.H>
#include <FL/x.H>
#include <FL/fl_draw.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
Fl_Double_Window *main_win=(Fl_Double_Window *)0;
Fl_Group *outer_group=(Fl_Group *)0;
Fl_Group *inner_grp1=(Fl_Group *)0;
Fl_Group *inner_grp2=(Fl_Group *)0;
Fl_Group *inner_grp3=(Fl_Group *)0;
/*************************************************************/
class cairo_box : public Fl_Box {
void draw(void); // draw method
cairo_surface_t *surface;
cairo_t *cairo_context;
float rr, gg, bb, aa;
void set_cairo_cxt(int wo, int ho);
public:
// constructor
cairo_box(int x, int y, int w, int h) : Fl_Box(x,y,w,h) {
surface = NULL; cairo_context = NULL;
rr = gg = bb = aa = 0.0;}
void set_rgb(float RR, float GG, float BB, float AA)
{rr = RR; gg = GG; bb = BB; aa = AA;}
};
/*************************************************************/
void cairo_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
// find the window enclosing this widget - probably main_win in this case!
Fl_Group *pt = this->parent();
while ((pt) && !(pt->as_window()))
{
pt = pt->parent();
}
if (!pt)
{
puts("No window context");
return;
}
/* Get a Cairo surface for the box, based on the enclosing window */
surface = cairo_xlib_surface_create(fl_display, fl_window, fl_visual->visual, pt->w(), pt->h());
#endif
/* Store the cairo context */
cairo_context = cairo_create(surface);
/* All Cairo co-ordinates are shifted by 0.5 pixels to correct anti-aliasing */
#ifndef __APPLE__ // Apple Quartz does not need the offset nudge, it seems...
cairo_translate(cairo_context, 0.5, 0.5);
#endif
}
/*************************************************************/
void cairo_box::draw(void) {
int xo = x(); // origin is current window position for Fl_Box
int yo = y();
int wo = w();
int ho = h();
/* 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);
// set cairo context
set_cairo_cxt(wo, ho);
// draw a 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, rr, gg, bb, aa);
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
/*************************************************************/
cairo_box *cairo1=(cairo_box *)0;
cairo_box *cairo2=(cairo_box *)0;
cairo_box *cairo3=(cairo_box *)0;
/*************************************************************/
static void cb_Quit(Fl_Button*, void*) {
main_win->hide();
}
/*************************************************************/
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);
outer_group = new Fl_Group(5, 5, 490, 450);
outer_group->begin();
inner_grp1 = new Fl_Group(5, 5, 160, 450);
inner_grp1->begin();
cairo1 = new cairo_box(7, 7, 156, 446);
cairo1->box(FL_FLAT_BOX);
cairo1->set_rgb(1.0,0,0,0.7);
inner_grp1->end();
inner_grp1->box(FL_DOWN_BOX);
inner_grp2 = new Fl_Group(165, 5, 160, 450);
inner_grp2->begin();
cairo2 = new cairo_box(167, 7, 156, 446);
cairo2->box(FL_FLAT_BOX);
cairo2->set_rgb(0,1.0,0,0.9);
inner_grp2->end();
inner_grp2->box(FL_DOWN_BOX);
inner_grp3 = new Fl_Group(325, 5, 170, 450);
inner_grp3->begin();
cairo3 = new cairo_box(327, 7, 166, 446);
cairo3->box(FL_FLAT_BOX);
cairo3->set_rgb(0,0,1.0, 0.3);
inner_grp3->end();
inner_grp3->box(FL_DOWN_BOX);
outer_group->end();
main_win->end();
main_win->resizable(outer_group);
main_win->label("Cairo Box Test");
main_win->show(argc, argv);
return Fl::run();
}
/* end of file */