@@ -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 | |||
@@ -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 ); | |||
@@ -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 | |||
@@ -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 |
@@ -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;} | |||
@@ -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 | |||
@@ -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 | |||
@@ -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* ) | |||
{ | |||
@@ -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; | |||
} | |||
@@ -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(); | |||
@@ -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.*/ | |||
@@ -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(); | |||
} | |||
/** | |||
@@ -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()); | |||
} | |||
@@ -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> | |||
@@ -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) { | |||
@@ -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) { | |||
@@ -170,6 +170,7 @@ CPPFILES = \ | |||
Clean_Theme.cxx \ | |||
Crystal_Theme.cxx \ | |||
themes.cxx \ | |||
Fl_Rectangle.cxx \ | |||
ps_image.cxx | |||
OBJCPPFILES = \ | |||
@@ -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 ); | |||
} | |||
@@ -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. | |||