New, driver-based Fl_Double_Window implementation.

git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3-porting@11303 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
Manolo Gouy 2016-03-06 21:33:07 +00:00
parent 7e2dc9daf5
commit acfeee6d78
10 changed files with 144 additions and 142 deletions

View File

@ -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);}

View File

@ -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

View File

@ -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

View File

@ -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();}
};

View File

@ -26,6 +26,7 @@
#include <src/drivers/GDI/Fl_GDI_Copy_Surface.H>
#elif defined(USE_SDL)
#include <src/drivers/SDL/Fl_SDL_Copy_Surface.H>
#elif defined(FL_PORTING)
# pragma message "FL_PORTING: implement class Fl_Copy_Surface::Helper for your platform"

View File

@ -19,58 +19,28 @@
Fl_Double_Window implementation.
*/
#include "config_lib.h"
#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Overlay_Window.H>
#include <FL/Fl_Printer.H>
#include <FL/x.H>
#include <FL/fl_draw.H>
#include <FL/Fl_Window_Driver.H>
// 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 <X11/extensions/Xdbe.h>
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 <I>also deletes all the children</I>. 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);
}

View File

@ -27,6 +27,7 @@
#include <src/drivers/GDI/Fl_GDI_Image_Surface.H>
#elif defined(USE_SDL)
#include <src/drivers/SDL/Fl_SDL_Image_Surface.H>
#elif defined(FL_PORTING)

View File

@ -19,6 +19,8 @@
#include "../../config_lib.h"
#include "Fl_Cocoa_Window_Driver.h"
#include <FL/Fl_Double_Window.H>
#include <FL/fl_draw.H>
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$".

View File

@ -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);
};

View File

@ -19,11 +19,29 @@
#include "../../config_lib.h"
#include "Fl_X11_Window_Driver.H"
#include <FL/fl_draw.H>
#if USE_XDBE
#include <X11/extensions/Xdbe.h>
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$".