From 91e15a2a10afa298cee67a76d380399c92a44b15 Mon Sep 17 00:00:00 2001 From: Jonathan Moore Liles Date: Fri, 27 Apr 2012 02:40:18 -0700 Subject: [PATCH] Replace X clipping with custom code based on FLTK2's Rectangle class to interact better with Cairo. --- FL/Fl.H | 4 +- FL/Fl_Device.H | 3 - FL/Fl_Menu_Window.H | 8 +- FL/Fl_Rectangle.H | 128 +++++++++++++++++++++++++++++++ FL/x.H | 9 ++- src/Fl.cxx | 43 +++++------ src/Fl_Cairo.cxx | 48 +++--------- src/Fl_Cairo_Graphics_Driver.cxx | 22 ------ src/Fl_Double_Window.cxx | 62 +++++++++++---- src/Fl_Group.cxx | 6 +- src/Fl_Menu_Window.cxx | 6 +- src/Fl_Overlay_Window.cxx | 8 +- src/Fl_Rectangle.cxx | 108 ++++++++++++++++++++++++++ src/Fl_Valuator.cxx | 2 +- src/Fl_Window.cxx | 11 --- src/Fl_x.cxx | 32 ++++++-- src/Makefile | 1 + src/fl_font_xft.cxx | 27 ++++++- src/fl_rect.cxx | 122 ++++++++++++++++++++--------- 19 files changed, 469 insertions(+), 181 deletions(-) create mode 100644 FL/Fl_Rectangle.H create mode 100644 src/Fl_Rectangle.cxx diff --git a/FL/Fl.H b/FL/Fl.H index 28fa338..5aefdf1 100644 --- a/FL/Fl.H +++ b/FL/Fl.H @@ -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 diff --git a/FL/Fl_Device.H b/FL/Fl_Device.H index 2ba6e2f..1fa18f7 100644 --- a/FL/Fl_Device.H +++ b/FL/Fl_Device.H @@ -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 ); diff --git a/FL/Fl_Menu_Window.H b/FL/Fl_Menu_Window.H index 85b8235..0c3bc3a 100644 --- a/FL/Fl_Menu_Window.H +++ b/FL/Fl_Menu_Window.H @@ -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 diff --git a/FL/Fl_Rectangle.H b/FL/Fl_Rectangle.H new file mode 100644 index 0000000..54fcb49 --- /dev/null +++ b/FL/Fl_Rectangle.H @@ -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 +#include # 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;} diff --git a/src/Fl.cxx b/src/Fl.cxx index 67de13a..bb1f1cd 100644 --- a/src/Fl.cxx +++ b/src/Fl.cxx @@ -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 diff --git a/src/Fl_Cairo.cxx b/src/Fl_Cairo.cxx index 8199932..153279c 100644 --- a/src/Fl_Cairo.cxx +++ b/src/Fl_Cairo.cxx @@ -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 diff --git a/src/Fl_Cairo_Graphics_Driver.cxx b/src/Fl_Cairo_Graphics_Driver.cxx index caabc6e..6b9ea92 100644 --- a/src/Fl_Cairo_Graphics_Driver.cxx +++ b/src/Fl_Cairo_Graphics_Driver.cxx @@ -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* ) { diff --git a/src/Fl_Double_Window.cxx b/src/Fl_Double_Window.cxx index e6cae3b..5d59506 100644 --- a/src/Fl_Double_Window.cxx +++ b/src/Fl_Double_Window.cxx @@ -32,6 +32,10 @@ #include #include +#include + +//#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; } diff --git a/src/Fl_Group.cxx b/src/Fl_Group.cxx index de7d488..36649c3 100644 --- a/src/Fl_Group.cxx +++ b/src/Fl_Group.cxx @@ -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(); diff --git a/src/Fl_Menu_Window.cxx b/src/Fl_Menu_Window.cxx index 8ef6fde..c6f6b31 100644 --- a/src/Fl_Menu_Window.cxx +++ b/src/Fl_Menu_Window.cxx @@ -41,18 +41,18 @@ #include 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.*/ diff --git a/src/Fl_Overlay_Window.cxx b/src/Fl_Overlay_Window.cxx index 5dfb1a4..8d366d0 100644 --- a/src/Fl_Overlay_Window.cxx +++ b/src/Fl_Overlay_Window.cxx @@ -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(); } /** diff --git a/src/Fl_Rectangle.cxx b/src/Fl_Rectangle.cxx new file mode 100644 index 0000000..13d9c27 --- /dev/null +++ b/src/Fl_Rectangle.cxx @@ -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 +#include + +/*! \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()); +} + diff --git a/src/Fl_Valuator.cxx b/src/Fl_Valuator.cxx index cfa4402..d094eef 100644 --- a/src/Fl_Valuator.cxx +++ b/src/Fl_Valuator.cxx @@ -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 not diff --git a/src/Fl_Window.cxx b/src/Fl_Window.cxx index 6f94097..6d07bde 100644 --- a/src/Fl_Window.cxx +++ b/src/Fl_Window.cxx @@ -38,9 +38,7 @@ #include -#ifdef __APPLE_QUARTZ__ #include -#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) { diff --git a/src/Fl_x.cxx b/src/Fl_x.cxx index 54dc3ff..0e3c993 100644 --- a/src/Fl_x.cxx +++ b/src/Fl_x.cxx @@ -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) { diff --git a/src/Makefile b/src/Makefile index c4268fa..2386aad 100644 --- a/src/Makefile +++ b/src/Makefile @@ -170,6 +170,7 @@ CPPFILES = \ Clean_Theme.cxx \ Crystal_Theme.cxx \ themes.cxx \ + Fl_Rectangle.cxx \ ps_image.cxx OBJCPPFILES = \ diff --git a/src/fl_font_xft.cxx b/src/fl_font_xft.cxx index 9e20fa0..87895fa 100644 --- a/src/fl_font_xft.cxx +++ b/src/fl_font_xft.cxx @@ -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 ); } diff --git a/src/fl_rect.cxx b/src/fl_rect.cxx index cf88525..026b098 100644 --- a/src/fl_rect.cxx +++ b/src/fl_rect.cxx @@ -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.