diff --git a/FL/Fl_Double_Window.H b/FL/Fl_Double_Window.H index e4ef883f5..46dd106f2 100644 --- a/FL/Fl_Double_Window.H +++ b/FL/Fl_Double_Window.H @@ -40,11 +40,11 @@ class FL_EXPORT Fl_Double_Window : public Fl_Window { protected: void flush(int eraseoverlay); +public: /** - Force double buffering, even if the OS already buffers windows - (overlays need that on MacOS and Windows2000) + Return non-null if this is an Fl_Overlay_Window object. */ - char force_doublebuffering_; + virtual Fl_Double_Window *as_overlay_window() {return NULL; } public: void show(); void show(int a, char **b) {Fl_Window::show(a,b);} diff --git a/FL/Fl_Image_Surface.H b/FL/Fl_Image_Surface.H index f556ed549..fa98a4bcd 100644 --- a/FL/Fl_Image_Surface.H +++ b/FL/Fl_Image_Surface.H @@ -53,7 +53,6 @@ class FL_EXPORT Fl_Image_Surface : public Fl_Widget_Surface { private: class Helper; Helper *platform_surface; - Fl_Offscreen offscreen(); protected: void translate(int x, int y); void untranslate(); @@ -69,6 +68,7 @@ public: void origin(int x, int y); int printable_rect(int *w, int *h); Fl_Offscreen get_offscreen_before_delete(); + Fl_Offscreen offscreen(); }; #endif // Fl_Image_Surface_H diff --git a/FL/Fl_Overlay_Window.H b/FL/Fl_Overlay_Window.H index de45b6c17..5114d3029 100644 --- a/FL/Fl_Overlay_Window.H +++ b/FL/Fl_Overlay_Window.H @@ -72,6 +72,7 @@ protected: Fl_Overlay_Window(int X, int Y, int W, int H, const char *l=0); public: void show(int a, char **b) {Fl_Double_Window::show(a,b);} + virtual Fl_Double_Window *as_overlay_window() {return this; } }; #endif diff --git a/FL/Fl_Window_Driver.H b/FL/Fl_Window_Driver.H index dea792669..540b6971f 100644 --- a/FL/Fl_Window_Driver.H +++ b/FL/Fl_Window_Driver.H @@ -40,6 +40,9 @@ public: static Fl_Window_Driver *newWindowDriver(Fl_Window *); virtual void take_focus() { } + virtual int double_flush(int eraseoverlay); + virtual void destroy_double_buffer(); + void draw() {w->draw();} }; diff --git a/src/Fl_Copy_Surface.cxx b/src/Fl_Copy_Surface.cxx index 475ee902e..53985e080 100644 --- a/src/Fl_Copy_Surface.cxx +++ b/src/Fl_Copy_Surface.cxx @@ -26,6 +26,7 @@ #include #elif defined(USE_SDL) +#include #elif defined(FL_PORTING) # pragma message "FL_PORTING: implement class Fl_Copy_Surface::Helper for your platform" diff --git a/src/Fl_Double_Window.cxx b/src/Fl_Double_Window.cxx index 243101f96..be9b016cc 100644 --- a/src/Fl_Double_Window.cxx +++ b/src/Fl_Double_Window.cxx @@ -19,58 +19,28 @@ Fl_Double_Window implementation. */ -#include "config_lib.h" #include #include #include #include #include #include +#include // On systems that support double buffering "naturally" the base // Fl_Window class will probably do double-buffer and this subclass // does nothing. -#if USE_XDBE - -#include - -static int use_xdbe; - -static int can_xdbe() { - static int tried; - if (!tried) { - tried = 1; - int event_base, error_base; - if (!XdbeQueryExtension(fl_display, &event_base, &error_base)) return 0; - Drawable root = RootWindow(fl_display,fl_screen); - int numscreens = 1; - XdbeScreenVisualInfo *a = XdbeGetVisualInfo(fl_display,&root,&numscreens); - if (!a) return 0; - for (int j = 0; j < a->count; j++) { - if (a->visinfo[j].visual == fl_visual->visualid - /*&& a->visinfo[j].perflevel > 0*/) { - use_xdbe = 1; break; - } - } - XdbeFreeVisualInfo(a); - } - return use_xdbe; -} -#endif - Fl_Double_Window::Fl_Double_Window(int W, int H, const char *l) -: Fl_Window(W,H,l), - force_doublebuffering_(0) +: Fl_Window(W,H,l) { type(FL_DOUBLE_WINDOW); } Fl_Double_Window::Fl_Double_Window(int X, int Y, int W, int H, const char *l) -: Fl_Window(X,Y,W,H,l), - force_doublebuffering_(0) +: Fl_Window(X,Y,W,H,l) { type(FL_DOUBLE_WINDOW); } @@ -111,126 +81,68 @@ void Fl_Double_Window::flush() {flush(0);} void Fl_Double_Window::flush(int eraseoverlay) { if (!shown()) return; make_current(); // make sure fl_gc is non-zero - Fl_X *myi = Fl_X::i(this); + Fl_Window_Driver *myi = (Fl_Window_Driver*)Fl_X::i(this); if (!myi) return; // window not yet created - if (!myi->other_xid) { -#if USE_XDBE - if (can_xdbe()) { - myi->other_xid = XdbeAllocateBackBufferName(fl_display, fl_xid(this), XdbeCopied); - myi->backbuffer_bad = 1; - } else -#endif -#if defined(USE_X11) || defined(WIN32) - myi->other_xid = fl_create_offscreen(w(), h()); - clear_damage(FL_DAMAGE_ALL); -#elif defined(__APPLE_QUARTZ__) // PORTME: platform double buffering - if (force_doublebuffering_) { - myi->other_xid = fl_create_offscreen(w(), h()); - clear_damage(FL_DAMAGE_ALL); - } -#elif defined(FL_PORTING) -# pragma message "FL_PORTING: Fl_Window_Driver - call a function to clear any graphics port damage flags" -#else -# error unsupported platform -#endif - } -#if USE_XDBE - if (use_xdbe) { - if (myi->backbuffer_bad || eraseoverlay) { - // Make sure we do a complete redraw... - if (myi->region) {XDestroyRegion(myi->region); myi->region = 0;} - clear_damage(FL_DAMAGE_ALL); - myi->backbuffer_bad = 0; - } - - // Redraw as needed... - if (damage()) { - fl_clip_region(myi->region); myi->region = 0; - fl_window = myi->other_xid; - draw(); - fl_window = myi->xid; - } - - // Copy contents of back buffer to window... - XdbeSwapInfo s; - s.swap_window = fl_xid(this); - s.swap_action = XdbeCopied; - XdbeSwapBuffers(fl_display, &s, 1); - return; - } else -#endif - if (damage() & ~FL_DAMAGE_EXPOSE) { - fl_clip_region(myi->region); myi->region = 0; -#ifdef WIN32 - void* _sgc = fl_graphics_driver->gc(); - HDC gc = fl_makeDC(myi->other_xid); - fl_graphics_driver->gc(gc); - int save = SaveDC(gc); - fl_restore_clip(); // duplicate region into new gc - draw(); - RestoreDC(gc, save); - DeleteDC(gc); - fl_graphics_driver->gc(_sgc); - //# if defined(FLTK_USE_CAIRO) - //if Fl::cairo_autolink_context() Fl::cairo_make_current(this); // capture gc changes automatically to update the cairo context adequately - //# endif -#elif defined(__APPLE__) // PORTME: Fl_Window_Driver - platform double buffering - if ( myi->other_xid ) { - fl_begin_offscreen( myi->other_xid ); - fl_clip_region( 0 ); - draw(); - fl_end_offscreen(); - } else { - draw(); - } -#elif defined(FL_PORTING) -# pragma message "FL_PORTING: manage double buffered drawing" -#else // X: - fl_window = myi->other_xid; - draw(); - fl_window = myi->xid; -#endif - } + int retval = myi->double_flush(eraseoverlay); + if (retval) return; if (eraseoverlay) fl_clip_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_graphics_driver->copy_offscreen(X, Y, W, H, myi->other_xid, X, Y); + if (myi->other_xid) { + int X,Y,W,H; fl_graphics_driver->clip_box(0,0,w(),h(),X,Y,W,H); + fl_graphics_driver->copy_offscreen(X, Y, W, H, myi->other_xid, X, Y); + } +} + +int Fl_Window_Driver::double_flush(int eraseoverlay) { + /* This is a working, platform-independent implementation. + Some platforms may re-implement it for their own logic: + - on Mac OS, the system double buffers all windows, so it is + reimplemented to do the same as Fl_Window::flush(), except for + Fl_Overlay_Window's which fall back on this implementation. + - on Xlib, it is reimplemented if the Xdbe extension is available. + */ + if (!other_xid) { + other_xid = fl_create_offscreen(w->w(), w->h()); + w->clear_damage(FL_DAMAGE_ALL); + } + if (w->damage() & ~FL_DAMAGE_EXPOSE) { + fl_clip_region(region); region = 0; + fl_begin_offscreen(other_xid); + fl_graphics_driver->clip_region( 0 ); + draw(); + fl_end_offscreen(); + } + return 0; } void Fl_Double_Window::resize(int X,int Y,int W,int H) { int ow = w(); int oh = h(); Fl_Window::resize(X,Y,W,H); -#if USE_XDBE - if (use_xdbe) { - Fl_X* myi = Fl_X::i(this); - if (myi && myi->other_xid && (ow < w() || oh < h())) { - // STR #2152: Deallocate the back buffer to force creation of a new one. - XdbeDeallocateBackBufferName(fl_display,myi->other_xid); - myi->other_xid = 0; - } - return; - } -#endif - Fl_X* myi = Fl_X::i(this); - if (myi && myi->other_xid && (ow != w() || oh != h())) { - fl_delete_offscreen(myi->other_xid); - myi->other_xid = 0; - } + Fl_Window_Driver *myi = (Fl_Window_Driver*)Fl_X::i(this); + if (myi && myi->other_xid && (ow < w() || oh < h())) + myi->destroy_double_buffer(); } void Fl_Double_Window::hide() { - Fl_X* myi = Fl_X::i(this); + Fl_Window_Driver *myi = (Fl_Window_Driver*)Fl_X::i(this); if (myi && myi->other_xid) { -#if USE_XDBE - if (!use_xdbe) -#endif - fl_delete_offscreen(myi->other_xid); + myi->destroy_double_buffer(); } Fl_Window::hide(); } +void Fl_Window_Driver::destroy_double_buffer() { + /* This is a working, platform-independent implementation. + Some platforms may re-implement it for their own logic: + - on Xlib, it is reimplemented if the Xdbe extension is available. + */ + fl_delete_offscreen(other_xid); + other_xid = 0; +} + + /** The destructor also deletes all the children. This allows a whole tree to be deleted at once, without having to keep a pointer to @@ -245,7 +157,6 @@ Fl_Overlay_Window::Fl_Overlay_Window(int W, int H, const char *l) : Fl_Double_Window(W,H,l) { overlay_ = 0; - force_doublebuffering_=1; image(0); } @@ -254,7 +165,6 @@ Fl_Overlay_Window::Fl_Overlay_Window(int X, int Y, int W, int H, const char *l) : Fl_Double_Window(X,Y,W,H,l) { overlay_ = 0; - force_doublebuffering_=1; image(0); } diff --git a/src/Fl_Image_Surface.cxx b/src/Fl_Image_Surface.cxx index 53663554a..de7c7a9f0 100644 --- a/src/Fl_Image_Surface.cxx +++ b/src/Fl_Image_Surface.cxx @@ -27,6 +27,7 @@ #include #elif defined(USE_SDL) +#include #elif defined(FL_PORTING) diff --git a/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.cxx b/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.cxx index 4a665a871..08a3184b9 100644 --- a/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.cxx +++ b/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.cxx @@ -19,6 +19,8 @@ #include "../../config_lib.h" #include "Fl_Cocoa_Window_Driver.h" +#include +#include Fl_Window_Driver *Fl_Window_Driver::newWindowDriver(Fl_Window *w) @@ -41,6 +43,15 @@ void Fl_Cocoa_Window_Driver::take_focus() set_key_window(); } +int Fl_Cocoa_Window_Driver::double_flush(int eraseoverlay) { + if ( ((Fl_Double_Window*)w)->as_overlay_window() ) { + Fl_Window_Driver::double_flush(eraseoverlay); + } else { + draw(); + } + return 0; +} + // // End of "$Id$". diff --git a/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.h b/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.h index b0c756aa1..e7f683689 100644 --- a/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.h +++ b/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.h @@ -47,6 +47,7 @@ class FL_EXPORT Fl_Cocoa_Window_Driver : public Fl_Window_Driver public: Fl_Cocoa_Window_Driver(Fl_Window*); virtual void take_focus(); + int double_flush(int eraseoverlay); }; diff --git a/src/drivers/X11/Fl_X11_Window_Driver.cxx b/src/drivers/X11/Fl_X11_Window_Driver.cxx index 0da90b246..2912169a9 100644 --- a/src/drivers/X11/Fl_X11_Window_Driver.cxx +++ b/src/drivers/X11/Fl_X11_Window_Driver.cxx @@ -19,11 +19,29 @@ #include "../../config_lib.h" #include "Fl_X11_Window_Driver.H" +#include +#if USE_XDBE +#include +static int can_xdbe(); // forward + +// class to be used only if Xdbe is used +class Fl_X11_Dbe_Window_Driver : public Fl_X11_Window_Driver { +public: + Fl_X11_Dbe_Window_Driver(Fl_Window *w) : Fl_X11_Window_Driver(w) {} + virtual int double_flush(int eraseoverlay); + virtual void destroy_double_buffer(); +}; +#endif Fl_Window_Driver *Fl_Window_Driver::newWindowDriver(Fl_Window *w) { - return new Fl_X11_Window_Driver(w); +#if USE_XDBE + if (can_xdbe()) // strictly necessary only for Fl_Double_Window, but does no harm for Fl_Window + return new Fl_X11_Dbe_Window_Driver(w); + else +#endif + return new Fl_X11_Window_Driver(w); } @@ -41,6 +59,62 @@ void Fl_X11_Window_Driver::take_focus() Fl_X::activate_window(xid); } +#if USE_XDBE + +static int can_xdbe() { // whether the Xdbe extension is usable + static int tried; + static int use_xdbe = 0; + if (!tried) { + tried = 1; + int event_base, error_base; + if (!XdbeQueryExtension(fl_display, &event_base, &error_base)) return 0; + Drawable root = RootWindow(fl_display,fl_screen); + int numscreens = 1; + XdbeScreenVisualInfo *a = XdbeGetVisualInfo(fl_display,&root,&numscreens); + if (!a) return 0; + for (int j = 0; j < a->count; j++) { + if (a->visinfo[j].visual == fl_visual->visualid) { + use_xdbe = 1; break; + } + } + XdbeFreeVisualInfo(a); + } + return use_xdbe; +} + +int Fl_X11_Dbe_Window_Driver::double_flush(int eraseoverlay) { + if (!other_xid) { + other_xid = XdbeAllocateBackBufferName(fl_display, xid, XdbeCopied); + backbuffer_bad = 1; + w->clear_damage(FL_DAMAGE_ALL); + } + if (backbuffer_bad || eraseoverlay) { + // Make sure we do a complete redraw... + if (region) {XDestroyRegion(region); region = 0;} + w->clear_damage(FL_DAMAGE_ALL); + backbuffer_bad = 0; + } + // Redraw as needed... + if (w->damage()) { + fl_clip_region(region); region = 0; + fl_window = other_xid; + draw(); + fl_window = xid; + } + // Copy contents of back buffer to window... + XdbeSwapInfo s; + s.swap_window = xid; + s.swap_action = XdbeCopied; + XdbeSwapBuffers(fl_display, &s, 1); + return 1; +} + +void Fl_X11_Dbe_Window_Driver::destroy_double_buffer() { + XdbeDeallocateBackBufferName(fl_display, other_xid); + other_xid = 0; +} + +#endif // USE_XDBE // // End of "$Id$".