Browse Source

Replace X clipping with custom code based on FLTK2's Rectangle class to interact better with Cairo.

tags/v1.3.1000
Jonathan Moore Liles 13 years ago
parent
commit
91e15a2a10
19 changed files with 469 additions and 181 deletions
  1. +3
    -1
      FL/Fl.H
  2. +0
    -3
      FL/Fl_Device.H
  3. +4
    -4
      FL/Fl_Menu_Window.H
  4. +128
    -0
      FL/Fl_Rectangle.H
  5. +6
    -3
      FL/x.H
  6. +20
    -23
      src/Fl.cxx
  7. +10
    -38
      src/Fl_Cairo.cxx
  8. +0
    -22
      src/Fl_Cairo_Graphics_Driver.cxx
  9. +48
    -14
      src/Fl_Double_Window.cxx
  10. +3
    -3
      src/Fl_Group.cxx
  11. +3
    -3
      src/Fl_Menu_Window.cxx
  12. +1
    -7
      src/Fl_Overlay_Window.cxx
  13. +108
    -0
      src/Fl_Rectangle.cxx
  14. +1
    -1
      src/Fl_Valuator.cxx
  15. +0
    -11
      src/Fl_Window.cxx
  16. +24
    -8
      src/Fl_x.cxx
  17. +1
    -0
      src/Makefile
  18. +23
    -4
      src/fl_font_xft.cxx
  19. +86
    -36
      src/fl_rect.cxx

+ 3
- 1
FL/Fl.H View File

@@ -1039,8 +1039,10 @@ public:
*/
public:

static cairo_surface_t * cairo_create_surface ( Window xid, int W, int H );

// Cairo support API
static cairo_t * cairo_make_current(Fl_Window* wi, Window w = 0);
static cairo_t * cairo_make_current( cairo_surface_t *cs, cairo_t *cc );
/** when FLTK_HAVE_CAIRO is defined and cairo_autolink_context() is true,
any current window dc is linked to a current context.
This is not the default, because it may not be necessary


+ 0
- 3
FL/Fl_Device.H View File

@@ -522,9 +522,6 @@ public:

void line_style(int style, int width=0, char* dashes=0);

void restore_clip ( void );

void arc( int x, int y, int w, int h, double a1, double a2 );
void pie( int x, int y, int w, int h, double a1, double a2 );
void arc( double x, double y, double r, double a1, double a2 );


+ 4
- 4
FL/Fl_Menu_Window.H View File

@@ -31,7 +31,7 @@
#ifndef Fl_Menu_Window_H
#define Fl_Menu_Window_H

#include "Fl_Double_Window.H"
#include "Fl_Single_Window.H"

/**
The Fl_Menu_Window widget is a window type used for menus. By
@@ -39,7 +39,7 @@
available so that the menu don't force the rest of the window to
redraw.
*/
class FL_EXPORT Fl_Menu_Window : public Fl_Double_Window {
class FL_EXPORT Fl_Menu_Window : public Fl_Single_Window {
public:
void show();
void erase();
@@ -48,10 +48,10 @@ public:
~Fl_Menu_Window();
/** Creates a new Fl_Menu_Window widget using the given size, and label string. */
Fl_Menu_Window(int W, int H, const char *l = 0)
: Fl_Double_Window(W,H,l) { image(0); }
: Fl_Single_Window(W,H,l) { image(0); }
/** Creates a new Fl_Menu_Window widget using the given position, size, and label string. */
Fl_Menu_Window(int X, int Y, int W, int H, const char *l = 0)
: Fl_Double_Window(X,Y,W,H,l) { image(0); }
: Fl_Single_Window(X,Y,W,H,l) { image(0); }
};

#endif


+ 128
- 0
FL/Fl_Rectangle.H View File

@@ -0,0 +1,128 @@
// "$Id: Fl_Rectangle.h 8500 2011-03-03 09:20:46Z bgbnbigben $"
//
// Copyright 1998-2006 by Bill Spitzak and others.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA.
//
// Please report all bugs and problems on the following page:
//
// http://www.fltk.org/str.php

#ifndef fltk_Fl_Rectangle_h
#define fltk_Fl_Rectangle_h

// rectangle macros that help keeping rectangle predicates as strict as possible
// even when not using rectangles in some situations (as when only using w h scalars)
// so that there is only one strict defintion for common predicates,
// if one change the following, it will be repercuted in all the core lib
#define FLTK_RECT_EMPTY(w,h) (w <= 0 || h <= 0)
// we should always use the same evaluation for center_x, center_y in all corelib code:
//#define FLTK_CENTER_X(coord, length) (coord + (length>>1))
//#define FLTK_CENTER_Y(coord, length) (coord + (length>>1))

class Fl_Rectangle {
int x_, y_, w_, h_;

public:

/*! Left edge */
int x() const {return x_;}
/*! Top edge */
int y() const {return y_;}
/*! Distance between left and right edges */
int w() const {return w_;}
/*! Distance between top and bottom edges */
int h() const {return h_;}
/*! Return x()+w(), the right edge of the rectangle. */
int r() const {return x_+w_;}
/*! Return y()+h(), the bottom edge of the rectangle. */
int b() const {return y_+h_;}
/*! Move the rectangle so the left edge is at \a v. */
void x(int v) {x_ = v;}
/*! Move the rectangle so the top edge is at \a v. */
void y(int v) {y_ = v;}
/*! Change w() by moving the right edge. x() does not change. */
void w(int v) {w_ = v;}
/*! Change h() by moving the bottom edge. y() does not change. */
void h(int v) {h_ = v;}
/*! Change x() without changing r(), by changing the width. */
void set_x(int v) {w_ -= v-x_; x_ = v;}
/*! Change y() without changing b(), by changing the height. */
void set_y(int v) {h_ -= v-y_; y_ = v;}
/*! Change r() without changing x(), by changine the width. */
void set_r(int v) {w_ = v-x_;}
/*! Change b() without changing y(), by changine the height. */
void set_b(int v) {h_ = v-y_;}
/*! Set x(), y(), w(), and h() all at once. */
void set(int x, int y, int w, int h) {x_=x; y_=y; w_=w; h_=h;}
/*! Sets x, y, w, h so that's it's centered or aligned (if flags!=0) inside the source r */
void set (const Fl_Rectangle& r, int w, int h, int flags = 0);
/*! Add \a d to x() without changing r() (it reduces w() by \a d). */
void move_x(int d) {x_ += d; w_ -= d;}
/*! Add \a d to y() without changing b() (it reduces h() by \a d). */
void move_y(int d) {y_ += d; h_ -= d;}
/*! Add \a d to r() and w(). */
void move_r(int d) {w_ += d;}
/*! Add \a d to b() and h(). */
void move_b(int d) {h_ += d;}
/*! Move all edges in by \a d. See also Symbol::inset() */
void inset(int d) {x_ += d; y_ += d; w_ -= 2*d; h_ -= 2*d;}
/*! Move entire rectangle by given distance in x and y. */
void move(int dx, int dy) {x_ += dx; y_ += dy;}
/*! True if w() or h() are less or equal to zero. */
bool empty() const {return FLTK_RECT_EMPTY(w_, h_);}
/*! Same as !empty(), true if w() and h() are both greater than zero. */
bool not_empty() const {return !FLTK_RECT_EMPTY(w_, h_);}
/*! Integer center position. Rounded to the left if w() is odd. */
int center_x() const {return x_+(w_>>1);}
/*! Integer center position. Rounded to lower y if h() is odd. */
int center_y() const {return y_+(h_>>1);}
/*! Where to put baseline to center current font nicely */
int baseline_y() const;

Fl_Rectangle() {}

/*! Constructor that sets x(), y(), w(), and h(). */
Fl_Rectangle(int x, int y, int w, int h) : x_(x), y_(y), w_(w), h_(h) {}

/*! Constructor that sets x() and y() to zero, and sets w() and h(). */
Fl_Rectangle(int w, int h) : x_(0), y_(0), w_(w), h_(h) {}

/*! Copy constructor. */
Fl_Rectangle(const Fl_Rectangle& r) : x_(r.x_),y_(r.y_),w_(r.w_),h_(r.h_) {}

/*! Constructor that calls set(). */
Fl_Rectangle(const Fl_Rectangle& r, int w, int h, int flags = 0) {set(r,w,h,flags);}

/*! True if rectangle contains the pixel who's upper-left corner is at x,y */
bool contains(int x, int y) const {return x>=x_ && y>=y_ && x<x_+w_ && y<y_+h_;}

/* returns true if the rectangles intersect at all */
bool intersects ( const Fl_Rectangle &r ) const
{
Fl_Rectangle r2( r );

r2.intersect( *this );

return ! r2.empty();
}

void merge(const Fl_Rectangle& r);
void intersect(const Fl_Rectangle& r);

};

#endif

+ 6
- 3
FL/x.H View File

@@ -46,6 +46,7 @@

# include "Enumerations.H"
#include <FL/Fl_Cairo.H>
#include <FL/Fl_Rectangle.H>

# ifdef WIN32
# include "win32.H"
@@ -64,7 +65,7 @@
# include "Fl_Window.H"
# include "Xutf8.h"
// Mirror X definition of Region to Fl_Region, for portability...
typedef Region Fl_Region;
typedef Fl_Rectangle * Fl_Region;

FL_EXPORT void fl_open_display();
FL_EXPORT void fl_open_display(Display*);
@@ -158,16 +159,18 @@ extern FL_EXPORT Fl_XFont_On_Demand fl_xfont;
class FL_EXPORT Fl_X {
public:
Window xid;
Window other_xid;
Window other_xid; /* for double buffering */
#if FLTK_HAVE_CAIRO
cairo_t *cc;
cairo_surface_t *cs;
cairo_t *other_cc; /* for double buffering */
cairo_surface_t *other_cs; /* for double buffering */
#endif
Fl_Window *w;
Fl_Region region;
Fl_X *next;
char wait_for_expose;
char backbuffer_bad; // used for XDBE
char cairo_surface_invalid;
static Fl_X* first;
static Fl_X* i(const Fl_Window* wi) {return wi->i;}
void setwindow(Fl_Window* wi) {w=wi; wi->i=this;}


+ 20
- 23
src/Fl.cxx View File

@@ -750,12 +750,10 @@ void Fl::flush() {
for (Fl_X* i = Fl_X::first; i; i = i->next) {
if (i->wait_for_expose) {damage_ = 1; continue;}
Fl_Window* wi = i->w;
// Fl::cairo_make_current(wi);
if (!wi->visible_r()) continue;
wi->make_current();
if (wi->damage()) {i->flush(); wi->clear_damage();}
if (wi->damage()) {wi->make_current(); i->flush(); wi->clear_damage();}
// destroy damage regions for windows that don't use them:
if (i->region) {XDestroyRegion(i->region); i->region = 0;}
if (i->region) {delete i->region; i->region = 0;}
}
}
#if defined(USE_X11)
@@ -1436,18 +1434,18 @@ void Fl_Window::hide() {
fl_window = 0;
#endif

if (ip->region) XDestroyRegion(ip->region);
if (ip->region) delete ip->region; ip->region = 0;

#if defined(USE_X11)
#if FLTK_HAVE_CAIRO
cairo_destroy( ip->cc ); ip->cc = 0;
cairo_surface_destroy( ip->cs ); ip->cs = 0;
#endif
# if USE_XFT
fl_destroy_xft_draw(ip->xid);
# endif
// this test makes sure ip->xid has not been destroyed already
if (ip->xid) XDestroyWindow(fl_display, ip->xid);
#if FLTK_HAVE_CAIRO
cairo_destroy( ip->cc ); ip->cc = NULL;
cairo_surface_destroy( ip->cs ); ip->cs = NULL;
#endif
#elif defined(WIN32)
// this little trickery seems to avoid the popup window stacking problem
HWND p = GetForegroundWindow();
@@ -1641,7 +1639,7 @@ void Fl_Widget::damage(uchar fl) {
// damage entire window by deleting the region:
Fl_X* i = Fl_X::i((Fl_Window*)this);
if (!i) return; // window not mapped, so ignore it
if (i->region) {XDestroyRegion(i->region); i->region = 0;}
if (i->region) {delete i->region; i->region = 0;}
damage_ |= fl;
Fl::damage(FL_DAMAGE_CHILD);
}
@@ -1676,9 +1674,7 @@ void Fl_Widget::damage(uchar fl, int X, int Y, int W, int H) {
// if we already have damage we must merge with existing region:
if (i->region) {
#if defined(USE_X11)
XRectangle R;
R.x = X; R.y = Y; R.width = W; R.height = H;
XUnionRectWithRegion(&R, i->region, i->region);
i->region->merge( Fl_Rectangle( X, Y, W, H ) );
#elif defined(WIN32)
Fl_Region R = XRectangleRegion(X, Y, W, H);
CombineRgn(i->region, i->region, R, RGN_OR);
@@ -1700,25 +1696,26 @@ void Fl_Widget::damage(uchar fl, int X, int Y, int W, int H) {
wi->damage_ |= fl;
} else {
// create a new region:
if (i->region) XDestroyRegion(i->region);
i->region = XRectangleRegion(X,Y,W,H);
if (i->region) delete i->region;
i->region = new Fl_Rectangle(X,Y,W,H);
wi->damage_ = fl;
}
Fl::damage(FL_DAMAGE_CHILD);
}
void Fl_Window::flush() {

make_current();

//if (damage() == FL_DAMAGE_EXPOSE && can_boxcheat(box())) fl_boxcheat = this;
/* FIXME: shouldn't this destroy the region? */
fl_clip_region(i->region); i->region = 0;


cairo_surface_flush( i->cs );
if ( ! i->cc )
{
i->cs = Fl::cairo_create_surface( i->xid, w(), h() );
i->cc = cairo_create( i->cs );
Fl::cairo_make_current( i->cs, i->cc );
}

draw();

#if FLTK_HAVE_CAIRO
cairo_surface_flush( i->cs );
#endif
}

#ifdef WIN32


+ 10
- 38
src/Fl_Cairo.cxx View File

@@ -53,48 +53,20 @@ cairo_surface_t * cairo_create_surface(void * gc, Window w, int W, int H) {

cairo_surface_t *fl_cairo_surface;
cairo_t *fl_cairo_context;
static Window real_xid;
static int W, H;

cairo_t *
Fl::cairo_make_current(Fl_Window* wi, Window w ) {
if (!wi) return NULL; // Precondition

if ( ! w )
w = wi->i->other_xid ? wi->i->other_xid : wi->i->xid;

if ( ( fl_cairo_context && fl_cairo_context == wi->i->cc ) &&
w && w == real_xid &&
wi->w() == W && wi->h() == H )
/* already current */
return wi->i->cc;

real_xid = w;
W = wi->w();
H = wi->h();

if ( wi->i->cs )
{
cairo_xlib_surface_set_drawable( wi->i->cs, w, wi->w(), wi->h() );
cairo_destroy( wi->i->cc );
wi->i->cc = 0;
}
else
{
wi->i->cs = cairo_create_surface(fl_gc, w, wi->w(), wi->h());
}
cairo_surface_t *
Fl::cairo_create_surface ( Window xid, int W, int H )
{
return ::cairo_create_surface( fl_gc, xid, W, H );
}

if ( ! wi->i->cc )
{
/* set this window's context to be the current one */
wi->i->cc = cairo_create( wi->i->cs );
}
cairo_t *
Fl::cairo_make_current( cairo_surface_t *cs, cairo_t *cc ) {

fl_cairo_surface = wi->i->cs;
fl_cairo_context = wi->i->cc;
fl_cairo_surface = cs;
fl_cairo_context = cc;

printf( "NTK: cairo_make_current()\n" );
return wi->i->cc;
return cc;
}

#endif // FLTK_HAVE_CAIRO


+ 0
- 22
src/Fl_Cairo_Graphics_Driver.cxx View File

@@ -132,28 +132,6 @@ Fl_Cairo_Graphics_Driver::Fl_Cairo_Graphics_Driver ( ) : Fl_Xlib_Graphics_Driv
/* fl_cairo_surface = 0; */
/* } */

void Fl_Cairo_Graphics_Driver::restore_clip ( void )
{
cairo_t *cr = Fl::cairo_cc();

if ( ! cr )
return;

Fl_Xlib_Graphics_Driver::restore_clip();

cairo_reset_clip( cr );

Fl_Region r = clip_region();

if ( r )
{
XRectangle rect;
XClipBox(r, &rect);
cairo_rectangle( cr, rect.x, rect.y, rect.width, rect.height );
cairo_clip( cr );
}
}

void Fl_Cairo_Graphics_Driver::line_style ( int style, int t, char* )
{


+ 48
- 14
src/Fl_Double_Window.cxx View File

@@ -32,6 +32,10 @@
#include <FL/x.H>
#include <FL/fl_draw.H>

#include <FL/Fl_Cairo.H>

//#define DEBUG_EXPOSE

// On systems that support double buffering "naturally" the base
// Fl_Window class will probably do double-buffer and this subclass
// does nothing.
@@ -305,8 +309,8 @@ void Fl_Double_Window::flush() {flush(0);}
and leaving the clip region set to the entire window.
*/
void Fl_Double_Window::flush(int eraseoverlay) {
//make_current(); // make sure fl_gc is non-zero
Fl_X *myi = Fl_X::i(this);

if (!myi->other_xid) {

#if defined(USE_X11) || defined(WIN32)
@@ -318,20 +322,20 @@ void Fl_Double_Window::flush(int eraseoverlay) {
clear_damage(FL_DAMAGE_ALL);
}


#else
# error unsupported platform
#endif
myi->other_cs = Fl::cairo_create_surface( myi->other_xid, w(), h() );
myi->other_cc = cairo_create( myi->other_cs );

#if FLTK_HAVE_CAIRO
Fl::cairo_make_current( this );
#endif
}
fl_clip_region(myi->region);

if (damage() & ~FL_DAMAGE_EXPOSE) {

Fl::cairo_make_current( myi->other_cs, myi->other_cc );
#ifdef WIN32
HDC _sgc = fl_gc;
fl_gc = fl_makeDC(myi->other_xid);
@@ -354,30 +358,46 @@ void Fl_Double_Window::flush(int eraseoverlay) {
#else // X:
fl_window = myi->other_xid;
// fl_restore_clip();
fl_clip_region(myi->region);

draw();

#if FLTK_HAVE_CAIRO
cairo_surface_flush( myi->cs );
cairo_surface_flush( myi->other_cs );
#endif

fl_window = myi->xid;

#if FLTK_HAVE_CAIRO
Fl::cairo_make_current( myi->cs, myi->cc );
#endif

// fl_restore_clip();
fl_clip_region(myi->region);

#endif
}
if (eraseoverlay) fl_clip_region(0);
// on Irix (at least) it is faster to reduce the area copied to
// the current clip region:

if (eraseoverlay)
{
int X,Y,W,H; fl_clip_box(0,0,w(),h(),X,Y,W,H);
if (myi->other_xid) fl_copy_offscreen(X, Y, W, H, myi->other_xid, X, Y);
fl_clip_region(0);
}

myi->region = 0;
// on Irix (at least) it is faster to reduce the area copied to
// the current clip region:
int X,Y,W,H; fl_clip_box(0,0,w(),h(),X,Y,W,H);
if (myi->other_xid) fl_copy_offscreen(X, Y, W, H, myi->other_xid, X, Y);

#ifdef DEBUG_EXPOSE
if ( damage() & FL_DAMAGE_EXPOSE )
{
#if FLTK_HAVE_CAIRO
fl_rectf( 0,0, w(), h(), fl_color_add_alpha( FL_RED, 50 ));
#endif
}
#endif
}

void Fl_Double_Window::resize(int X,int Y,int W,int H) {
@@ -386,6 +406,13 @@ void Fl_Double_Window::resize(int X,int Y,int W,int H) {
Fl_Window::resize(X,Y,W,H);
Fl_X* myi = Fl_X::i(this);
if (myi && myi->other_xid && (ow != w() || oh != h())) {
#if FLTK_HAVE_CAIRO
if ( myi->other_cs )
{
cairo_destroy( myi->other_cc ); myi->other_cc = 0;
cairo_surface_destroy( myi->other_cs ); myi->other_cs = 0;
}
#endif
fl_delete_offscreen(myi->other_xid);
myi->other_xid = 0;
}
@@ -394,6 +421,13 @@ void Fl_Double_Window::resize(int X,int Y,int W,int H) {
void Fl_Double_Window::hide() {
Fl_X* myi = Fl_X::i(this);
if (myi && myi->other_xid) {
#if FLTK_HAVE_CAIRO
if ( myi->other_cs )
{
cairo_destroy( myi->other_cc ); myi->other_cc = 0;
cairo_surface_destroy( myi->other_cs ); myi->other_cs = 0;
}
#endif
fl_delete_offscreen(myi->other_xid);
myi->other_xid = 0;
}


+ 3
- 3
src/Fl_Group.cxx View File

@@ -755,8 +755,8 @@ void Fl_Group::draw() {
\sa Fl_Group::draw_child(Fl_Widget& widget) const
*/
void Fl_Group::update_child(Fl_Widget& widget) const {
if (widget.damage() && widget.visible() && widget.type() < FL_WINDOW &&
fl_not_clipped(widget.x(), widget.y(), widget.w(), widget.h())) {
if (widget.damage() && widget.visible() && widget.type() < FL_WINDOW &&
fl_not_clipped(widget.x(), widget.y(), widget.w(), widget.h())) {
widget.draw();
widget.clear_damage();
}
@@ -769,7 +769,7 @@ void Fl_Group::update_child(Fl_Widget& widget) const {
The damage bits are cleared after drawing.
*/
void Fl_Group::draw_child(Fl_Widget& widget) const {
if (widget.visible() && widget.type() < FL_WINDOW &&
if (widget.visible() && widget.type() < FL_WINDOW &&
fl_not_clipped(widget.x(), widget.y(), widget.w(), widget.h())) {
widget.clear_damage(FL_DAMAGE_ALL);
widget.draw();


+ 3
- 3
src/Fl_Menu_Window.cxx View File

@@ -41,18 +41,18 @@
#include <stdio.h>

void Fl_Menu_Window::show() {
Fl_Double_Window::show();
Fl_Single_Window::show();
}

void Fl_Menu_Window::flush() {
Fl_Double_Window::flush();
Fl_Single_Window::flush();
}

// Fix the colormap flashing on Maximum Impact Graphics by erasing the
// menu before unmapping it:
void Fl_Menu_Window::hide() {
// erase();
Fl_Double_Window::hide();
Fl_Single_Window::hide();
}

/** Destroys the window and all of its children.*/


+ 1
- 7
src/Fl_Overlay_Window.cxx View File

@@ -56,13 +56,7 @@ void Fl_Overlay_Window::flush() {
clear_damage((uchar)(damage()&~FL_DAMAGE_OVERLAY));
Fl_Double_Window::flush(erase_overlay);
Fl_X* myi = Fl_X::i(this);
#if FLTK_HAVE_CAIRO
Fl::cairo_make_current( this, myi->xid );
#endif
draw_overlay();
#if FLTK_HAVE_CAIRO
Fl::cairo_make_current( this, myi->other_xid );
#endif
draw_overlay();
}

/**


+ 108
- 0
src/Fl_Rectangle.cxx View File

@@ -0,0 +1,108 @@
// "$Id: Fl_Rectangle.h 8500 2011-03-03 09:20:46Z bgbnbigben $"
//
// Copyright 1998-2006 by Bill Spitzak and others.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA.
//
// Please report all bugs and problems on the following page:
//
// http://www.fltk.org/str.php

#include <FL/Fl_Rectangle.H>
#include <FL/fl_draw.H>

/*! \class Fl_Rectangle
Describes an integer-sized rectangle. This is the base class of
Widget, and also used a lot to pass rectangular areas to drawing
functions. Almost all the functions are inline.

Negative w() or h() is supposed to mean an empty and thus
invisible rectangle, but some code will treat the rectangle as
reflected about x or y. Set the size to zero to make sure you
have an empty one.
*/

/*! \fn Rectangle::Rectangle()
The default constructor does not put anything into the fields!
You can either call set() or just modify the x_, y_, w_, and h_
variables directly.
*/

/** Initialize to the size w,h. The rectangle is placed inside the
source rectangle \a r either centered or against an edge depending
on the FL_ALIGN values in \a flags. For centered alignment if the
difference in sizes is odd, it always rounds up and left.
Default value for \a flags is to center in both directions.
*/
void Fl_Rectangle::set(const Fl_Rectangle& r, int w, int h, int flags) {
if (flags & FL_ALIGN_LEFT) {
if (flags & FL_ALIGN_RIGHT && w > r.w()) x_ = r.r()-w;
else x_ = r.x();
} else if (flags & FL_ALIGN_RIGHT) {
x_ = r.r()-w;
} else {
x_ = r.x()+((r.w()-w)>>1);
// fabien: shouldn't it consider the case r is smaller to avoid negative values ?
// WAS: no, it is supposed to center at all times. The right-shift
// instead of divide-by-2 is to avoid shifting as it goes negative.
// fabien : well while debugging i observed the shift doesn't avoid
// to get negative value at least on Win32
// WAS: no, it is *supposed* to return a negative value! I want the
// rectangle "centered" even if it is *bigger*.
// if (x_<0) x_=0;
}
if (flags & FL_ALIGN_TOP) {
if (flags & FL_ALIGN_BOTTOM && h > r.h()) y_ = r.b()-h;
else y_ = r.y();
} else if (flags & FL_ALIGN_BOTTOM) {
y_ = r.b()-h;
} else {
y_ = r.y()+((r.h()-h)>>1);
// see above
// if (y_<0) y_=0;
}
w_ = w;
h_ = h;
}

/**
Replace the value with the union of this rectangle and \a R
(ie the rectangle that surrounds both of these rectangles).
If one rectangle is empty(), the other is returned unchanged
(ie it does not union in the degenerate point of that rectangle).
*/
void Fl_Rectangle::merge(const Fl_Rectangle& R) {
if (R.empty()) return;
if (empty()) {*this = R; return;}
if (R.x() < x()) set_x(R.x());
if (R.r() > r()) set_r(R.r());
if (R.y() < y()) set_y(R.y());
if (R.b() > b()) set_b(R.b());
}

/**
Replace the value with the intersection of this rectangle and \a R.
If the rectangles do not intersect, the result may have negative
width and/or height, this means empty() will return true, but some
code may still draw this rectangle.
*/
void Fl_Rectangle::intersect(const Fl_Rectangle& R) {
if (R.x() > x()) set_x(R.x());
if (R.r() < r()) set_r(R.r());
if (R.y() > y()) set_y(R.y());
if (R.b() < b()) set_b(R.b());
}


+ 1
- 1
src/Fl_Valuator.cxx View File

@@ -66,7 +66,7 @@ void Fl_Valuator::precision(int p) {
for (B = 1; p--;) B *= 10;
}
/** Asks for partial redraw */
void Fl_Valuator::value_damage() {damage(FL_DAMAGE_EXPOSE);} // by default do partial-redraw
void Fl_Valuator::value_damage() {damage(FL_DAMAGE_USER1);} // by default do partial-redraw

/**
Sets the current value. The new value is <I>not</I>


+ 0
- 11
src/Fl_Window.cxx View File

@@ -38,9 +38,7 @@

#include <FL/Fl_Cairo.H>

#ifdef __APPLE_QUARTZ__
#include <FL/fl_draw.H>
#endif

char *Fl_Window::default_xclass_ = 0L;

@@ -113,14 +111,6 @@ void Fl_Window::draw() {
}
draw_children();

#if FLTK_HAVE_CAIRO
cairo_surface_flush( i->cs );
#endif

#ifdef __APPLE_QUARTZ__
// on OS X, windows have no frame. To resize a window, we drag the lower right
// corner. This code draws a little ribbed triangle for dragging.
extern CGContextRef fl_gc;
if (fl_gc && !parent() && resizable() && (!size_range_set || minh!=maxh || minw!=maxw)) {
int dx = Fl::box_dw(box())-Fl::box_dx(box());
int dy = Fl::box_dh(box())-Fl::box_dy(box());
@@ -139,7 +129,6 @@ void Fl_Window::draw() {
fl_line(x1--, y1, x2, y2--);
}
}
#endif
}

void Fl_Window::label(const char *name) {


+ 24
- 8
src/Fl_x.cxx View File

@@ -1665,6 +1665,9 @@ void Fl_Window::resize(int X,int Y,int W,int H) {
} else
XMoveWindow(fl_display, i->xid, X, Y);
}

if ( is_a_resize && i )
i->cairo_surface_invalid = 1;
}

////////////////////////////////////////////////////////////////
@@ -1679,14 +1682,16 @@ Fl_X* Fl_X::set_xid(Fl_Window* win, Window winxid) {
xp->xid = winxid;
xp->other_xid = 0;
#if FLTK_HAVE_CAIRO
xp->cc = 0;
xp->cs = 0;
xp->cs = Fl::cairo_create_surface( winxid, win->w(), win->h() );
xp->cc = cairo_create( xp->cs );
xp->cairo_surface_invalid = 0;
xp->other_cc = 0;
xp->other_cs = 0;
#endif
xp->setwindow(win);
xp->next = Fl_X::first;
xp->region = 0;
xp->wait_for_expose = 1;
xp->backbuffer_bad = 1;
// xp->backbuffer_bad = 1;
Fl_X::first = xp;
if (win->modal()) {Fl::modal_ = win; fl_fix_focus();}
return xp;
@@ -2038,12 +2043,23 @@ void Fl_Window::make_current() {
if (!gc) gc = XCreateGC(fl_display, i->xid, 0, 0);
fl_window = i->xid;
fl_gc = gc;
current_ = this;
fl_clip_region(0);

#ifdef FLTK_HAVE_CAIRO
Fl::cairo_make_current(this);
if ( i->cairo_surface_invalid && i->cc )
{
cairo_destroy( i->cc ); i->cc = 0;
cairo_surface_destroy( i->cs ); i->cs = 0;
}

if ( ! i->cc )
{
i->cs = Fl::cairo_create_surface( i->xid, w(), h() );
i->cc = cairo_create( i->cs );
}
Fl::cairo_make_current( i->cs, i->cc );
#endif
current_ = this;

fl_clip_region(i->region);
}

Window fl_xid_(const Fl_Window *w) {


+ 1
- 0
src/Makefile View File

@@ -170,6 +170,7 @@ CPPFILES = \
Clean_Theme.cxx \
Crystal_Theme.cxx \
themes.cxx \
Fl_Rectangle.cxx \
ps_image.cxx
OBJCPPFILES = \


+ 23
- 4
src/fl_font_xft.cxx View File

@@ -113,6 +113,8 @@ void *fl_xftfont = 0;
//const char* fl_encoding_ = "iso8859-1";
const char* fl_encoding_ = "iso10646-1";

extern Region XRegionFromRectangle ( Fl_Rectangle *rg );

static void fl_xft_font(Fl_Xlib_Graphics_Driver *driver, Fl_Font fnum, Fl_Fontsize size, int angle) {
if (fnum==-1) { // special case to stop font caching
driver->Fl_Graphics_Driver::font(0, 0);
@@ -599,8 +601,14 @@ void Fl_Xlib_Graphics_Driver::draw(const char *str, int n, int x, int y) {
else //if (draw_window != fl_window)
XftDrawChange(draw_, draw_window = fl_window);

Region region = fl_clip_region();
if (region && XEmptyRegion(region)) return;
Region region = XRegionFromRectangle( fl_clip_region() );

if (region && XEmptyRegion(region))
{
XDestroyRegion( region );
return;
}
XftDrawSetClip(draw_, region);

// Use fltk's color allocator, copy the results to match what
@@ -619,6 +627,8 @@ void Fl_Xlib_Graphics_Driver::draw(const char *str, int n, int x, int y) {
#else
XftDrawString32(draw_, &color, font_descriptor()->font, x, y, (XftChar32 *)buffer, n);
#endif

if ( region ) XDestroyRegion( region );
}

void Fl_Xlib_Graphics_Driver::draw(int angle, const char *str, int n, int x, int y) {
@@ -644,8 +654,15 @@ static void fl_drawUCS4(Fl_Graphics_Driver *driver, const FcChar32 *str, int n,
else //if (draw_window != fl_window)
XftDrawChange(draw_, draw_window = fl_window);

Region region = fl_clip_region();
if (region && XEmptyRegion(region)) return;

Region region = XRegionFromRectangle( fl_clip_region() );

if (region && XEmptyRegion(region))
{
XDestroyRegion( region );
return;
}
XftDrawSetClip(draw_, region);

// Use fltk's color allocator, copy the results to match what
@@ -659,6 +676,8 @@ static void fl_drawUCS4(Fl_Graphics_Driver *driver, const FcChar32 *str, int n,
color.color.alpha = 0xffff;

XftDrawString32(draw_, &color, driver->font_descriptor()->font, x, y, (FcChar32 *)str, n);

if ( region ) XDestroyRegion( region );
}




+ 86
- 36
src/fl_rect.cxx View File

@@ -511,18 +511,33 @@ void Fl_Graphics_Driver::point(int x, int y) {
#endif
}

Region XRegionFromRectangle ( Fl_Rectangle *rg )
{
if ( rg )
{
Region region = XCreateRegion();

XRectangle rr;
rr.x = rg->x();
rr.y = rg->y();
rr.width = rg->w();
rr.height = rg->h();
XUnionRectWithRegion( &rr, region, region );

return region;
}

return 0;
}

////////////////////////////////////////////////////////////////

#if !defined(WIN32) && !defined(__APPLE__)
// Missing X call: (is this the fastest way to init a 1-rectangle region?)
// MSWindows equivalent exists, implemented inline in win32.H
Fl_Region XRectangleRegion(int x, int y, int w, int h) {
XRectangle R;
clip_to_short(x, y, w, h);
R.x = x; R.y = y; R.width = w; R.height = h;
Fl_Region r = XCreateRegion();
XUnionRectWithRegion(&R, r, r);
return r;
return new Fl_Rectangle( x, y, w, h );
}
#endif

@@ -530,8 +545,14 @@ void Fl_Graphics_Driver::restore_clip() {
fl_clip_state_number++;
Fl_Region r = rstack[rstackptr];
#if defined(USE_X11)
if (r) XSetRegion(fl_display, fl_gc, r);
else XSetClipMask(fl_display, fl_gc, 0);
if (r)
{
Region xr = XRegionFromRectangle( r );
XSetRegion(fl_display, fl_gc, xr );
XDestroyRegion( xr );
}
else
XSetClipMask(fl_display, fl_gc, 0);
#elif defined(WIN32)
SelectClipRgn(fl_gc, r); //if r is NULL, clip is automatically cleared
#elif defined(__APPLE_QUARTZ__)
@@ -552,12 +573,32 @@ void Fl_Graphics_Driver::restore_clip() {
#else
# error unsupported platform
#endif

#if FLTK_HAVE_CAIRO
cairo_t *cr = fl_cairo_context;

if ( cr )
{
cairo_reset_clip( cr );

if ( r )
{
// cairo_set_source_rgb( cr, 0, 1, 0 );
cairo_rectangle( cr, r->x(), r->y(), r->w(), r->h() );
// cairo_stroke_preserve( cr );

cairo_clip( cr );
}
}
#endif

}

void Fl_Graphics_Driver::clip_region(Fl_Region r) {
Fl_Region oldr = rstack[rstackptr];
if (oldr && r != oldr ) XDestroyRegion(oldr);
rstack[rstackptr] = r;
if (oldr && r != oldr ) delete oldr;
rstack[rstackptr] = r ? new Fl_Rectangle( *r ) : 0;
fl_restore_clip();
}

@@ -568,14 +609,16 @@ Fl_Region Fl_Graphics_Driver::clip_region() {
void Fl_Graphics_Driver::push_clip(int x, int y, int w, int h) {
Fl_Region r;
if (w > 0 && h > 0) {
r = XRectangleRegion(x,y,w,h);
r = new Fl_Rectangle( x, y, w, h );
Fl_Region current = rstack[rstackptr];
if (current) {
#if defined(USE_X11)
Fl_Region temp = XCreateRegion();
XIntersectRegion(current, r, temp);
XDestroyRegion(r);
r = temp;
r->intersect( *current );
if ( r->empty() )
{
delete r;
r = new Fl_Rectangle( 0, 0, 0, 0 );
}
#elif defined(WIN32)
CombineRgn(r,r,current,RGN_AND);
#elif defined(__APPLE_QUARTZ__)
@@ -587,7 +630,7 @@ void Fl_Graphics_Driver::push_clip(int x, int y, int w, int h) {
}
} else { // make empty clip region:
#if defined(USE_X11)
r = XCreateRegion();
r = new Fl_Rectangle( 0, 0, 0, 0 );
#elif defined(WIN32)
r = CreateRectRgn(0,0,0,0);
#elif defined(__APPLE_QUARTZ__)
@@ -612,7 +655,7 @@ void Fl_Graphics_Driver::push_no_clip() {
void Fl_Graphics_Driver::pop_clip() {
if (rstackptr > 0) {
Fl_Region oldr = rstack[rstackptr--];
if (oldr) XDestroyRegion(oldr);
if (oldr) delete oldr;
} else Fl::warning("fl_pop_clip: clip stack underflow!\n");
fl_restore_clip();
}
@@ -623,8 +666,8 @@ int Fl_Graphics_Driver::not_clipped(int x, int y, int w, int h) {
if (!r) return 1;
#if defined (USE_X11)
// get rid of coordinates outside the 16-bit range the X calls take.
if (clip_to_short(x,y,w,h)) return 0; // clipped
return XRectInRegion(r, x, y, w, h);
// if (clip_to_short(x,y,w,h)) return 0; // clipped
return r->intersects( Fl_Rectangle( x, y, w, h ) );
#elif defined(WIN32)
RECT rect;
if (Fl_Surface_Device::surface()->class_name() == Fl_Printer::class_id) { // in case of print context, convert coords from logical to device
@@ -652,25 +695,32 @@ int Fl_Graphics_Driver::clip_box(int x, int y, int w, int h, int& X, int& Y, int
X = x; Y = y; W = w; H = h;
Fl_Region r = rstack[rstackptr];
if (!r) return 0;
#if defined(USE_X11)
switch (XRectInRegion(r, x, y, w, h)) {
case RectangleOut: // completely outside
W = H = 0;
return 2;
case RectangleIn: // completely inside:
return 0;
default: // partial:
break;

Fl_Rectangle rec( x, y, w, h );
rec.intersect( *r );

X = rec.x(); Y = rec.y(); W = rec.w(); H = rec.h();

if ( r->contains( x, y ) && r->contains( x + w - 1, y + h - 1 ) )
{
/* completely inside */
return 0;
}
Fl_Region rr = XRectangleRegion(x,y,w,h);
Fl_Region temp = XCreateRegion();
XIntersectRegion(r, rr, temp);
XRectangle rect;
XClipBox(temp, &rect);
X = rect.x; Y = rect.y; W = rect.width; H = rect.height;
XDestroyRegion(temp);
XDestroyRegion(rr);

if ( rec.empty() )
{
H = W = 0;
/* completely outside */
return 2;
}

/* partial */

return 1;

#if defined(USE_X11)

#elif defined(WIN32)
// The win32 API makes no distinction between partial and complete
// intersection, so we have to check for partial intersection ourselves.


Loading…
Cancel
Save