diff --git a/CMake/options.cmake b/CMake/options.cmake index 602663fe6..1785d99ee 100644 --- a/CMake/options.cmake +++ b/CMake/options.cmake @@ -498,6 +498,7 @@ endif (OPTION_USE_XCURSOR) if (X11_Xft_FOUND) option (OPTION_USE_XFT "use lib Xft" ON) option (OPTION_USE_PANGO "use lib Pango" OFF) + option (OPTION_CAIROXLIB "draw to X11 windows with Cairo" OFF) endif (X11_Xft_FOUND) # test option compatibility: Pango requires Xft @@ -529,6 +530,10 @@ if ((X11_Xft_FOUND OR OPTION_USE_WAYLAND) AND OPTION_USE_PANGO) find_library(HAVE_LIB_CAIRO cairo ${CMAKE_LIBRARY_PATH}) find_library(HAVE_LIB_GOBJECT gobject-2.0 ${CMAKE_LIBRARY_PATH}) set (USE_PANGO TRUE) + if (OPTION_CAIROXLIB) + set (USE_CAIRO_GRAPHICS_DRIVER TRUE) +message (STATUS "USE_CAIRO_GRAPHICS_DRIVER=" ${USE_CAIRO_GRAPHICS_DRIVER}) + endif (OPTION_CAIROXLIB) list (APPEND FLTK_LDLIBS -lpango-1.0 -lpangoxft-1.0 -lpangocairo-1.0 -lcairo -lgobject-2.0) if (APPLE) get_filename_component(PANGO_L_PATH ${HAVE_LIB_PANGO} PATH) diff --git a/configh.cmake.in b/configh.cmake.in index cf537af82..8470fb0d0 100644 --- a/configh.cmake.in +++ b/configh.cmake.in @@ -115,6 +115,14 @@ #cmakedefine01 USE_PANGO +/* + * USE_CAIRO_GRAPHICS_DRIVER + * + * Use the cairo library for all drawings to X11 windows. + */ + +#cmakedefine01 USE_CAIRO_GRAPHICS_DRIVER + /* * HAVE_XFIXES: * diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7d3b9a59d..0d9715531 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -227,6 +227,9 @@ if (FLTK_USE_X11) ) if (USE_PANGO) set (DRIVER_FILES ${DRIVER_FILES} drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx) + if (USE_CAIRO_GRAPHICS_DRIVER) + set (DRIVER_FILES ${DRIVER_FILES} drivers/Cairo/Fl_Display_Cairo_Graphics_Driver.cxx) + endif (USE_CAIRO_GRAPHICS_DRIVER) endif (USE_PANGO) else () set (DRIVER_FILES ${DRIVER_FILES} diff --git a/src/Fl_x.cxx b/src/Fl_x.cxx index 6933ee05d..3be7a9c29 100644 --- a/src/Fl_x.cxx +++ b/src/Fl_x.cxx @@ -53,6 +53,11 @@ # include # include "Xutf8.h" +#if USE_CAIRO_GRAPHICS_DRIVER +# include +# include +#endif // USE_CAIRO_GRAPHICS_DRIVER + #define USE_XRANDR (HAVE_DLSYM && HAVE_DLFCN_H) // means attempt to dynamically load libXrandr.so #if USE_XRANDR #include @@ -2084,7 +2089,15 @@ void Fl_X11_Window_Driver::resize(int X,int Y,int W,int H) { else if (!is_a_resize && !is_a_move) return; if (is_a_resize) { pWindow->Fl_Group::resize(X,Y,W,H); - if (shown()) {pWindow->redraw();} + if (shown()) { +#if USE_CAIRO_GRAPHICS_DRIVER + if (!pWindow->as_gl_window() && cairo_) { + float s = Fl::screen_driver()->scale(screen_num()); + cairo_xlib_surface_set_size(cairo_get_target(cairo_), (W>0 ? int(W*s) : 1), (H>0 ? int(H*s) : 1)); + } +#endif + pWindow->redraw(); + } } else { x(X); y(Y); if (fl_xim_win && Fl::focus()) { diff --git a/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx b/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx index 3a7d4aa9b..305bd5ef6 100644 --- a/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx +++ b/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx @@ -930,7 +930,11 @@ static Fl_Fontdesc built_in_table[] = { // Pango font names {"D050000L"}, // FL_ZAPF_DINGBATS }; -FL_EXPORT Fl_Fontdesc *fl_fonts = built_in_table; +#if USE_CAIRO_GRAPHICS_DRIVER + Fl_Fontdesc *fl_fonts = built_in_table; +#else + extern Fl_Fontdesc *fl_fonts; +#endif void Fl_Cairo_Graphics_Driver::init_built_in_fonts() { static int i = 0; diff --git a/src/drivers/X11/Fl_X11_Window_Driver.H b/src/drivers/X11/Fl_X11_Window_Driver.H index 71370d13a..7cb27422f 100644 --- a/src/drivers/X11/Fl_X11_Window_Driver.H +++ b/src/drivers/X11/Fl_X11_Window_Driver.H @@ -26,6 +26,11 @@ #include "../../Fl_Window_Driver.H" #include #include // for Cursor + +#if USE_CAIRO_GRAPHICS_DRIVER +typedef struct _cairo cairo_t; +#endif // USE_CAIRO_GRAPHICS_DRIVER + class Fl_Bitmap; /* @@ -73,6 +78,10 @@ private: int screen_num_; void screen_num(int n) { screen_num_ = n; } #endif // USE_XFT +#if USE_CAIRO_GRAPHICS_DRIVER + cairo_t *cairo_; + cairo_t *offscreen_cairo_; +#endif // USE_CAIRO_GRAPHICS_DRIVER void decorated_win_size(int &w, int &h); void combine_mask(); void shape_bitmap_(Fl_Image* b); diff --git a/src/drivers/X11/Fl_X11_Window_Driver.cxx b/src/drivers/X11/Fl_X11_Window_Driver.cxx index 9b5196358..5a773e6ec 100644 --- a/src/drivers/X11/Fl_X11_Window_Driver.cxx +++ b/src/drivers/X11/Fl_X11_Window_Driver.cxx @@ -19,6 +19,10 @@ #include "Fl_X11_Window_Driver.H" #include "Fl_X11_Screen_Driver.H" #include "../Xlib/Fl_Xlib_Graphics_Driver.H" +#if USE_CAIRO_GRAPHICS_DRIVER +# include +# include "../Cairo/Fl_Display_Cairo_Graphics_Driver.H" +#endif // USE_CAIRO_GRAPHICS_DRIVER #include "../../Fl_Screen_Driver.H" #include @@ -57,6 +61,10 @@ Fl_X11_Window_Driver::Fl_X11_Window_Driver(Fl_Window *win) #if USE_XFT screen_num_ = -1; #endif +#if USE_CAIRO_GRAPHICS_DRIVER + cairo_ = NULL; + offscreen_cairo_ = NULL; +#endif } @@ -155,9 +163,17 @@ void Fl_X11_Window_Driver::flush_double(int erase_overlay) pWindow->make_current(); // make sure fl_gc is non-zero Fl_X *i = Fl_X::i(pWindow); if (!other_xid) { - other_xid = fl_create_offscreen(w(), h()); + other_xid = fl_create_offscreen(w(), h()); +#if USE_CAIRO_GRAPHICS_DRIVER + fl_begin_offscreen(other_xid); + offscreen_cairo_ = ((Fl_Cairo_Graphics_Driver*)fl_graphics_driver)->cr(); + fl_end_offscreen(); +#endif pWindow->clear_damage(FL_DAMAGE_ALL); } +#if USE_CAIRO_GRAPHICS_DRIVER + ((Fl_Display_Cairo_Graphics_Driver*)fl_graphics_driver)->activate(offscreen_cairo_); +#endif if (pWindow->damage() & ~FL_DAMAGE_EXPOSE) { fl_clip_region(i->region); i->region = 0; fl_window = other_xid; @@ -374,7 +390,21 @@ void Fl_X11_Window_Driver::make_current() { } fl_window = fl_xid(pWindow); fl_graphics_driver->clip_region(0); -#if USE_XFT + +#if USE_CAIRO_GRAPHICS_DRIVER + float scale = Fl::screen_scale(screen_num()); // get the screen scaling factor + if (!pWindow->as_double_window()) { + if (!cairo_) { + int W = pWindow->w() * scale, H = pWindow->h() * scale; + cairo_surface_t *s = cairo_xlib_surface_create(fl_display, fl_window, fl_visual->visual, W, H); + cairo_ = cairo_create(s); + cairo_surface_destroy(s); + cairo_save(cairo_); + } + ((Fl_Display_Cairo_Graphics_Driver*)fl_graphics_driver)->activate(cairo_); + } + fl_graphics_driver->scale(scale); +#elif USE_XFT ((Fl_Xlib_Graphics_Driver*)fl_graphics_driver)->scale(Fl::screen_driver()->scale(screen_num())); #endif diff --git a/src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.cxx b/src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.cxx index 0343e9a9c..903939bc5 100644 --- a/src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.cxx +++ b/src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.cxx @@ -21,6 +21,12 @@ #include #include "Fl_Xlib_Graphics_Driver.H" #include "../X11/Fl_X11_Screen_Driver.H" +#if USE_CAIRO_GRAPHICS_DRIVER +# include +# include "../Cairo/Fl_Display_Cairo_Graphics_Driver.H" +# include +#endif // USE_CAIRO_GRAPHICS_DRIVER + class Fl_Xlib_Copy_Surface_Driver : public Fl_Copy_Surface_Driver { friend class Fl_Copy_Surface_Driver; @@ -33,6 +39,9 @@ protected: void set_current(); void translate(int x, int y); void untranslate(); +#if USE_CAIRO_GRAPHICS_DRIVER + cairo_t *cairo_; +#endif }; @@ -43,11 +52,23 @@ Fl_Copy_Surface_Driver *Fl_Copy_Surface_Driver::newCopySurfaceDriver(int w, int Fl_Xlib_Copy_Surface_Driver::Fl_Xlib_Copy_Surface_Driver(int w, int h) : Fl_Copy_Surface_Driver(w, h) { +#if USE_CAIRO_GRAPHICS_DRIVER + driver(new Fl_Display_Cairo_Graphics_Driver()); +#else driver(new Fl_Xlib_Graphics_Driver()); +#endif float s = Fl_Graphics_Driver::default_driver().scale(); - ((Fl_Xlib_Graphics_Driver*)driver())->scale(s); + driver()->scale(s); oldwindow = fl_window; xid = fl_create_offscreen(w,h); +#if USE_CAIRO_GRAPHICS_DRIVER + cairo_surface_t *surf = cairo_xlib_surface_create(fl_display, xid, fl_visual->visual, w * s, h * s); + cairo_ = cairo_create(surf); + cairo_surface_destroy(surf); + cairo_scale(cairo_, 1/s, 1/s); + cairo_save(cairo_); + ((Fl_Display_Cairo_Graphics_Driver*)driver())->activate(cairo_); +#endif driver()->push_no_clip(); fl_window = xid; driver()->color(FL_WHITE); @@ -74,6 +95,9 @@ void Fl_Xlib_Copy_Surface_Driver::set_current() { Fl_Surface_Device::set_current(); oldwindow = fl_window; fl_window = xid; +#if USE_CAIRO_GRAPHICS_DRIVER + ((Fl_Display_Cairo_Graphics_Driver*)driver())->activate(cairo_); +#endif } void Fl_Xlib_Copy_Surface_Driver::end_current() { @@ -82,10 +106,20 @@ void Fl_Xlib_Copy_Surface_Driver::end_current() { } void Fl_Xlib_Copy_Surface_Driver::translate(int x, int y) { +#if USE_CAIRO_GRAPHICS_DRIVER + cairo_save(cairo_); + cairo_translate(cairo_, x, y); +#else ((Fl_Xlib_Graphics_Driver*)driver())->translate_all(x, y); +#endif + } void Fl_Xlib_Copy_Surface_Driver::untranslate() { +#if USE_CAIRO_GRAPHICS_DRIVER + cairo_restore(cairo_); +#else ((Fl_Xlib_Graphics_Driver*)driver())->untranslate_all(); +#endif } diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.cxx b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.cxx index 14c56c040..78020931f 100644 --- a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.cxx +++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.cxx @@ -20,6 +20,9 @@ #include "Fl_Font.H" #include #include +#if USE_CAIRO_GRAPHICS_DRIVER +# include "../Cairo/Fl_Display_Cairo_Graphics_Driver.H" +#endif #include #include @@ -36,7 +39,11 @@ extern char *fl_get_font_xfld(int fnum, int size); */ Fl_Graphics_Driver *Fl_Graphics_Driver::newMainGraphicsDriver() { +#if USE_CAIRO_GRAPHICS_DRIVER + return new Fl_Display_Cairo_Graphics_Driver(); +#else return new Fl_Xlib_Graphics_Driver(); +#endif } GC Fl_Xlib_Graphics_Driver::gc_ = NULL; diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx index 5e27c71bc..f1ad484c2 100644 --- a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx +++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx @@ -109,7 +109,9 @@ static Fl_Fontdesc built_in_table[] = { #endif // USE_PANGO +#if ! USE_CAIRO_GRAPHICS_DRIVER Fl_Fontdesc* fl_fonts = built_in_table; +#endif Fl_Fontsize Fl_Xlib_Graphics_Driver::size_unscaled() { return (Fl_Fontsize)(size_); diff --git a/src/drivers/Xlib/Fl_Xlib_Image_Surface_Driver.cxx b/src/drivers/Xlib/Fl_Xlib_Image_Surface_Driver.cxx index 89fe4a100..8abb3555d 100644 --- a/src/drivers/Xlib/Fl_Xlib_Image_Surface_Driver.cxx +++ b/src/drivers/Xlib/Fl_Xlib_Image_Surface_Driver.cxx @@ -17,6 +17,10 @@ #include "Fl_Xlib_Graphics_Driver.H" #include #include "../../Fl_Screen_Driver.H" +#if USE_CAIRO_GRAPHICS_DRIVER +# include +# include "../Cairo/Fl_Display_Cairo_Graphics_Driver.H" +#endif // USE_CAIRO_GRAPHICS_DRIVER class Fl_Xlib_Image_Surface_Driver : public Fl_Image_Surface_Driver { virtual void end_current(); @@ -28,6 +32,9 @@ public: void translate(int x, int y); void untranslate(); Fl_RGB_Image *image(); +#if USE_CAIRO_GRAPHICS_DRIVER + cairo_t *cairo_; +#endif }; Fl_Image_Surface_Driver *Fl_Image_Surface_Driver::newImageSurfaceDriver(int w, int h, int high_res, Fl_Offscreen off) @@ -39,15 +46,24 @@ Fl_Xlib_Image_Surface_Driver::Fl_Xlib_Image_Surface_Driver(int w, int h, int hig float d = 1; if (!off) { fl_open_display(); - d = fl_graphics_driver->scale(); + d = /*fl_graphics_driver->*/Fl_Graphics_Driver::default_driver().scale(); if (d != 1 && high_res) { w = int(w*d); h = int(h*d); } offscreen = XCreatePixmap(fl_display, RootWindow(fl_display, fl_screen), w, h, fl_visual->depth); } +#if USE_CAIRO_GRAPHICS_DRIVER + driver(new Fl_Display_Cairo_Graphics_Driver()); + cairo_surface_t *s = cairo_xlib_surface_create(fl_display, offscreen, fl_visual->visual, w, h); + cairo_ = cairo_create(s); + cairo_surface_destroy(s); + cairo_save(cairo_); + ((Fl_Display_Cairo_Graphics_Driver*)driver())->activate(cairo_); +#else driver(new Fl_Xlib_Graphics_Driver()); - if (d != 1 && high_res) ((Fl_Xlib_Graphics_Driver*)driver())->scale(d); +#endif + if (d != 1 && high_res) driver()->scale(d); } Fl_Xlib_Image_Surface_Driver::~Fl_Xlib_Image_Surface_Driver() { @@ -59,14 +75,26 @@ void Fl_Xlib_Image_Surface_Driver::set_current() { Fl_Surface_Device::set_current(); pre_window = fl_window; fl_window = offscreen; +#if USE_CAIRO_GRAPHICS_DRIVER + ((Fl_Display_Cairo_Graphics_Driver*)driver())->activate(cairo_); +#endif } void Fl_Xlib_Image_Surface_Driver::translate(int x, int y) { +#if USE_CAIRO_GRAPHICS_DRIVER + cairo_save(cairo_); + cairo_translate(cairo_, x, y); +#else ((Fl_Xlib_Graphics_Driver*)driver())->translate_all(x, y); +#endif } void Fl_Xlib_Image_Surface_Driver::untranslate() { +#if USE_CAIRO_GRAPHICS_DRIVER + cairo_restore(cairo_); +#else ((Fl_Xlib_Graphics_Driver*)driver())->untranslate_all(); +#endif } Fl_RGB_Image* Fl_Xlib_Image_Surface_Driver::image() diff --git a/src/drivers/Cairo/Fl_Display_Cairo_Graphics_Driver.H b/src/drivers/Cairo/Fl_Display_Cairo_Graphics_Driver.H new file mode 100644 index 000000000..1bbf1890d --- /dev/null +++ b/src/drivers/Cairo/Fl_Display_Cairo_Graphics_Driver.H @@ -0,0 +1,39 @@ +// +// Support for using Cairo to draw into X11 windows for the Fast Light Tool Kit (FLTK). +// +// Copyright 2022 by Bill Spitzak and others. +// +// This library is free software. Distribution and use rights are outlined in +// the file "COPYING" which should have been included with this file. If this +// file is missing or damaged, see the license at: +// +// https://www.fltk.org/COPYING.php +// +// Please see the following page on how to report bugs and issues: +// +// https://www.fltk.org/bugs.php +// + +/* \file + Declaration of class Fl_Display_Cairo_Graphics_Driver. +*/ + +#ifndef FL_DISPLAY_CAIRO_GRAPHICS_DRIVER_H +# define FL_DISPLAY_CAIRO_GRAPHICS_DRIVER_H + +#include "Fl_Cairo_Graphics_Driver.H" + +class Fl_Display_Cairo_Graphics_Driver : public Fl_Cairo_Graphics_Driver { +private: + static void *gc_; +public: + virtual ~Fl_Display_Cairo_Graphics_Driver(); + void activate(cairo_t *cr); + virtual void scale(float f); + virtual float scale() {return Fl_Graphics_Driver::scale();} + virtual void gc(void *value); + virtual void* gc(); + virtual void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy); + }; + +#endif // FL_DISPLAY_CAIRO_GRAPHICS_DRIVER_H diff --git a/src/drivers/Cairo/Fl_Display_Cairo_Graphics_Driver.cxx b/src/drivers/Cairo/Fl_Display_Cairo_Graphics_Driver.cxx new file mode 100644 index 000000000..860ed63e2 --- /dev/null +++ b/src/drivers/Cairo/Fl_Display_Cairo_Graphics_Driver.cxx @@ -0,0 +1,79 @@ +// +// Support for using Cairo to draw into X11 windows for the Fast Light Tool Kit (FLTK). +// +// Copyright 2022 by Bill Spitzak and others. +// +// This library is free software. Distribution and use rights are outlined in +// the file "COPYING" which should have been included with this file. If this +// file is missing or damaged, see the license at: +// +// https://www.fltk.org/COPYING.php +// +// Please see the following page on how to report bugs and issues: +// +// https://www.fltk.org/bugs.php +// + +/* \file + Implementation of class Fl_Display_Cairo_Graphics_Driver . +*/ + +#include "Fl_Display_Cairo_Graphics_Driver.H" +#include +#include +#include + +void *Fl_Display_Cairo_Graphics_Driver::gc_ = NULL; + + +Fl_Display_Cairo_Graphics_Driver::~Fl_Display_Cairo_Graphics_Driver() { + if (cairo_)cairo_destroy(cairo_); +} + + +void Fl_Display_Cairo_Graphics_Driver::activate(cairo_t *cr) { + if (dummy_pango_layout_) { + cairo_surface_t *surf = cairo_get_target(cairo_); + cairo_destroy(cairo_); + cairo_surface_destroy(surf); + g_object_unref(dummy_pango_layout_); + dummy_pango_layout_ = NULL; + pango_layout_ = NULL; + } + if (!pango_layout_) { + pango_layout_ = pango_cairo_create_layout(cr); + } + cairo_ = cr; + cairo_restore(cairo_); + line_style(0); + cairo_save(cairo_); + cairo_scale(cairo_, scale(), scale()); + cairo_translate(cairo_, 0.5, 0.5); +} + + +void Fl_Display_Cairo_Graphics_Driver::scale(float f) { + Fl_Graphics_Driver::scale(f); + if (cairo_) { + cairo_restore(cairo_); + cairo_save(cairo_); + cairo_scale(cairo_, f, f); + cairo_translate(cairo_, 0.5, 0.5); + } +} + + +void Fl_Display_Cairo_Graphics_Driver::copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy) { + XCopyArea(fl_display, pixmap, fl_window, (GC)Fl_Graphics_Driver::default_driver().gc(), int(srcx*scale()), int(srcy*scale()), int(w*scale()), int(h*scale()), int(x*scale()), int(y*scale())); +} + + +void Fl_Display_Cairo_Graphics_Driver::gc(void *value) { + gc_ = value; + fl_gc = (GC)gc_; +} + + +void *Fl_Display_Cairo_Graphics_Driver::gc() { + return gc_; +}