summaryrefslogtreecommitdiff
path: root/src/drivers/Xlib
diff options
context:
space:
mode:
authorMatthias Melcher <fltk@matthiasm.com>2016-01-26 20:17:47 +0000
committerMatthias Melcher <fltk@matthiasm.com>2016-01-26 20:17:47 +0000
commit5892993cbcf77e322f51475820d19f8307375df7 (patch)
tree314dd6627e5a44a6027febf8b2f9ea53fc8fdfb9 /src/drivers/Xlib
parent12e85b882aedccfae4836dd8c72bd546e1be408e (diff)
Preliminary commit of porting Xlib drivers to the new naming scheme
git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3-porting@11053 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
Diffstat (limited to 'src/drivers/Xlib')
-rw-r--r--src/drivers/Xlib/Fl_Xlib_Graphics_Driver.h112
-rw-r--r--src/drivers/Xlib/Fl_Xlib_Graphics_Driver_arci.cxx42
-rw-r--r--src/drivers/Xlib/Fl_Xlib_Graphics_Driver_color.cxx351
-rw-r--r--src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_x.cxx676
-rw-r--r--src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx1081
-rw-r--r--src/drivers/Xlib/Fl_Xlib_Graphics_Driver_line_style.cxx71
-rw-r--r--src/drivers/Xlib/Fl_Xlib_Graphics_Driver_rect.cxx339
-rw-r--r--src/drivers/Xlib/Fl_Xlib_Graphics_Driver_vertex.cxx116
8 files changed, 2788 insertions, 0 deletions
diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.h b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.h
new file mode 100644
index 000000000..255e5f16b
--- /dev/null
+++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.h
@@ -0,0 +1,112 @@
+//
+// "$Id$"
+//
+// Definition of classes Fl_Device, Fl_Graphics_Driver, Fl_Surface_Device, Fl_Display_Device
+// for the Fast Light Tool Kit (FLTK).
+//
+// Copyright 2010-2014 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:
+//
+// http://www.fltk.org/COPYING.php
+//
+// Please report all bugs and problems on the following page:
+//
+// http://www.fltk.org/str.php
+//
+
+/**
+ \file Fl_Xlib_Graphics_Driver.h
+ \brief Definition of X11 Xlib graphics driver.
+ */
+
+#ifndef FL_CFG_GFX_XLIB_H
+#define FL_CFG_GFX_XLIB_H
+
+#include <FL/Fl_Device.H>
+
+/**
+ \brief The Xlib-specific graphics class.
+ *
+ This class is implemented only on the Xlib platform.
+ */
+class FL_EXPORT Fl_Xlib_Graphics_Driver : public Fl_Graphics_Driver {
+public:
+ static const char *class_id;
+ const char *class_name() {return class_id;};
+ void draw(const char* str, int n, int x, int y);
+ void draw(int angle, const char *str, int n, int x, int y);
+ void rtl_draw(const char* str, int n, int x, int y);
+ void font(Fl_Font face, Fl_Fontsize size);
+ void draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy);
+ void draw(Fl_Bitmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy);
+ void draw(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy);
+ void draw_image(const uchar* buf, int X,int Y,int W,int H, int D=3, int L=0);
+ void draw_image(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=3);
+ void draw_image_mono(const uchar* buf, int X,int Y,int W,int H, int D=1, int L=0);
+ void draw_image_mono(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=1);
+ double width(const char *str, int n);
+ double width(unsigned int c);
+ void text_extents(const char*, int n, int& dx, int& dy, int& w, int& h);
+ int height();
+ int descent();
+ void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy);
+#if ! defined(FL_DOXYGEN)
+ void copy_offscreen_with_alpha(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy);
+#endif
+protected:
+ // --- implementation is in src/fl_rect.cxx which includes src/cfg_gfx/xlib_rect.cxx
+ void point(int x, int y);
+ void rect(int x, int y, int w, int h);
+ void rectf(int x, int y, int w, int h);
+ void line(int x, int y, int x1, int y1);
+ void line(int x, int y, int x1, int y1, int x2, int y2);
+ void xyline(int x, int y, int x1);
+ void xyline(int x, int y, int x1, int y2);
+ void xyline(int x, int y, int x1, int y2, int x3);
+ void yxline(int x, int y, int y1);
+ void yxline(int x, int y, int y1, int x2);
+ void yxline(int x, int y, int y1, int x2, int y3);
+ void loop(int x0, int y0, int x1, int y1, int x2, int y2);
+ void loop(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3);
+ void polygon(int x0, int y0, int x1, int y1, int x2, int y2);
+ void polygon(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3);
+ // --- clipping
+ void push_clip(int x, int y, int w, int h);
+ int clip_box(int x, int y, int w, int h, int &X, int &Y, int &W, int &H);
+ int not_clipped(int x, int y, int w, int h);
+ void push_no_clip();
+ void pop_clip();
+ void restore_clip();
+ // --- implementation is in src/fl_vertex.cxx which includes src/cfg_gfx/xxx_rect.cxx
+ void begin_complex_polygon();
+ void transformed_vertex(double xf, double yf);
+ void vertex(double x, double y);
+ void end_points();
+ void end_line();
+ void end_loop();
+ void end_polygon();
+ void end_complex_polygon();
+ void gap();
+ void circle(double x, double y, double r);
+ // --- implementation is in src/fl_arc.cxx which includes src/cfg_gfx/xxx_arc.cxx if needed
+ // using void Fl_Graphics_Driver::arc(double x, double y, double r, double start, double end);
+ // --- implementation is in src/fl_arci.cxx which includes src/cfg_gfx/xxx_arci.cxx
+ 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);
+ // --- implementation is in src/fl_line_style.cxx which includes src/cfg_gfx/xxx_line_style.cxx
+ void line_style(int style, int width=0, char* dashes=0);
+ // --- implementation is in src/fl_color.cxx which includes src/cfg_gfx/xxx_color.cxx
+ void color(Fl_Color c);
+ Fl_Color color() { return color_; }
+ void color(uchar r, uchar g, uchar b);
+};
+
+
+#endif // FL_CFG_GFX_XLIB_H
+
+//
+// End of "$Id$".
+//
diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_arci.cxx b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_arci.cxx
new file mode 100644
index 000000000..118e683a1
--- /dev/null
+++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_arci.cxx
@@ -0,0 +1,42 @@
+//
+// "$Id$"
+//
+// Arc (integer) drawing functions for the Fast Light Tool Kit (FLTK).
+//
+// Copyright 1998-2010 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:
+//
+// http://www.fltk.org/COPYING.php
+//
+// Please report all bugs and problems on the following page:
+//
+// http://www.fltk.org/str.php
+//
+
+#ifndef FL_CFG_GFX_XLIB_ARCI_CXX
+#define FL_CFG_GFX_XLIB_ARCI_CXX
+
+/**
+ \file xlib_arci.cxx
+ \brief Utility functions for drawing circles using integers
+*/
+
+void Fl_Xlib_Graphics_Driver::arc(int x,int y,int w,int h,double a1,double a2) {
+ if (w <= 0 || h <= 0) return;
+ XDrawArc(fl_display, fl_window, fl_gc, x,y,w-1,h-1, int(a1*64),int((a2-a1)*64));
+}
+
+void Fl_Xlib_Graphics_Driver::pie(int x,int y,int w,int h,double a1,double a2) {
+ if (w <= 0 || h <= 0) return;
+ XDrawArc(fl_display, fl_window, fl_gc, x,y,w-1,h-1, int(a1*64),int((a2-a1)*64));
+ XFillArc(fl_display, fl_window, fl_gc, x,y,w-1,h-1, int(a1*64),int((a2-a1)*64));
+}
+
+#endif // FL_CFG_GFX_XLIB_ARCI_CXX
+
+//
+// End of "$Id$".
+//
diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_color.cxx b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_color.cxx
new file mode 100644
index 000000000..e7e9d0cf7
--- /dev/null
+++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_color.cxx
@@ -0,0 +1,351 @@
+//
+// "$Id$"
+//
+// Color functions for the Fast Light Tool Kit (FLTK).
+//
+// Copyright 1998-2010 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:
+//
+// http://www.fltk.org/COPYING.php
+//
+// Please report all bugs and problems on the following page:
+//
+// http://www.fltk.org/str.php
+//
+
+// Implementation of fl_color(i), fl_color(r,g,b).
+
+// FIXME: all the global functions in this file should probably be protected
+// members of the driver class. Starting with 1.4 we will allow multiple drivers
+// to co-exist, creating conflicts with multipe mapping.
+
+// FIXME: maybe we can forget about color mapping and assume RGB?
+
+// Also code to look at the X visual and figure out the best way to turn
+// a color into a pixel value.
+
+// SGI compiler seems to have problems with unsigned char arguments
+// being used to index arrays. So I always copy them to an integer
+// before use.
+
+# include "../Fl_XColor.H"
+# include <FL/Fl.H>
+# include <FL/x.H>
+# include <FL/fl_draw.H>
+
+////////////////////////////////////////////////////////////////
+// figure_out_visual() calculates masks & shifts for generating
+// pixels in true-color visuals:
+
+uchar fl_redmask; /**< color mask used in current color map handling */
+uchar fl_greenmask; /**< color mask used in current color map handling */
+uchar fl_bluemask; /**< color mask used in current color map handling */
+
+int fl_redshift; /**< color shift used in current color map handling */
+int fl_greenshift; /**< color shift used in current color map handling */
+int fl_blueshift; /**< color shift used in current color map handling */
+int fl_extrashift; /**< color shift used in current color map handling */
+
+static uchar beenhere;
+
+static void figure_out_visual() {
+ beenhere = 1;
+ if (!fl_visual->red_mask || !fl_visual->green_mask || !fl_visual->blue_mask){
+# if USE_COLORMAP
+ fl_redmask = 0;
+ return;
+# else
+ Fl::fatal("Requires true color visual");
+# endif
+ }
+
+ // get the bit masks into a more useful form:
+ int i,j,m;
+
+ for (i = 0, m = 1; m; i++, m<<=1) if (fl_visual->red_mask & m) break;
+ for (j = i; m; j++, m<<=1) if (!(fl_visual->red_mask & m)) break;
+ fl_redshift = j-8;
+ fl_redmask = (j-i >= 8) ? 0xFF : 0xFF-(255>>(j-i));
+
+ for (i = 0, m = 1; m; i++, m<<=1) if (fl_visual->green_mask & m) break;
+ for (j = i; m; j++, m<<=1) if (!(fl_visual->green_mask & m)) break;
+ fl_greenshift = j-8;
+ fl_greenmask = (j-i >= 8) ? 0xFF : 0xFF-(255>>(j-i));
+
+ for (i = 0, m = 1; m; i++, m<<=1) if (fl_visual->blue_mask & m) break;
+ for (j = i; m; j++, m<<=1) if (!(fl_visual->blue_mask & m)) break;
+ fl_blueshift = j-8;
+ fl_bluemask = (j-i >= 8) ? 0xFF : 0xFF-(255>>(j-i));
+
+ i = fl_redshift;
+ if (fl_greenshift < i) i = fl_greenshift;
+ if (fl_blueshift < i) i = fl_blueshift;
+ if (i < 0) {
+ fl_extrashift = -i;
+ fl_redshift -= i; fl_greenshift -= i; fl_blueshift -= i;
+ } else
+ fl_extrashift = 0;
+
+}
+
+static unsigned fl_cmap[256] = {
+#include "../fl_cmap.h" // this is a file produced by "cmap.cxx":
+};
+
+# if HAVE_OVERLAY
+/** HAVE_OVERLAY determines whether fl_xmap is one or two planes */
+Fl_XColor fl_xmap[2][256];
+/** HAVE_OVERLAY determines whether fl_overlay is variable or defined as 0 */
+uchar fl_overlay;
+Colormap fl_overlay_colormap;
+XVisualInfo* fl_overlay_visual;
+ulong fl_transparent_pixel;
+# else
+/** HAVE_OVERLAY determines whether fl_xmap is one or two planes */
+Fl_XColor fl_xmap[1][256];
+/** HAVE_OVERLAY determines whether fl_overlay is variable or defined as 0 */
+# define fl_overlay 0
+# endif
+
+void Fl_Xlib_Graphics_Driver::color(Fl_Color i) {
+ if (i & 0xffffff00) {
+ unsigned rgb = (unsigned)i;
+ fl_color((uchar)(rgb >> 24), (uchar)(rgb >> 16), (uchar)(rgb >> 8));
+ } else {
+ Fl_Graphics_Driver::color(i);
+ if(!fl_gc) return; // don't get a default gc if current window is not yet created/valid
+ XSetForeground(fl_display, fl_gc, fl_xpixel(i));
+ }
+}
+
+void Fl_Xlib_Graphics_Driver::color(uchar r,uchar g,uchar b) {
+ Fl_Graphics_Driver::color( fl_rgb_color(r, g, b) );
+ if(!fl_gc) return; // don't get a default gc if current window is not yet created/valid
+ XSetForeground(fl_display, fl_gc, fl_xpixel(r,g,b));
+}
+
+/** \addtogroup fl_attributes
+ @{ */
+////////////////////////////////////////////////////////////////
+// Get an rgb color. This is easy for a truecolor visual. For
+// colormapped it picks the closest color out of the cube in the
+// fltk colormap. However if this color cube entry has been
+// requested before, you will get the earlier requested color, and
+// even this may be approximated if the X colormap was full.
+
+/**
+ Returns the X pixel number used to draw the given rgb color.
+ This is the X pixel that fl_color() would use.
+ \param[in] r,g,b color components
+ \return X pixel number
+*/
+ulong fl_xpixel(uchar r,uchar g,uchar b) {
+ if (!beenhere) figure_out_visual();
+# if USE_COLORMAP
+ if (!fl_redmask) {
+ // find closest entry in the colormap:
+ Fl_Color i =
+ fl_color_cube(r*FL_NUM_RED/256,g*FL_NUM_GREEN/256,b*FL_NUM_BLUE/256);
+ Fl_XColor &xmap = fl_xmap[fl_overlay][i];
+ if (xmap.mapped) return xmap.pixel;
+ // if not black or white, change the entry to be an exact match:
+ if (i != FL_COLOR_CUBE && i != 0xFF)
+ fl_cmap[i] = (r<<24)|(g<<16)|(b<<8);
+ return fl_xpixel(i); // allocate an X color
+ }
+# endif
+ return
+ (((r&fl_redmask) << fl_redshift)+
+ ((g&fl_greenmask)<<fl_greenshift)+
+ ((b&fl_bluemask)<< fl_blueshift)
+ ) >> fl_extrashift;
+}
+
+////////////////////////////////////////////////////////////////
+// Get a color out of the fltk colormap. Again for truecolor
+// visuals this is easy. For colormap this actually tries to allocate
+// an X color, and does a least-squares match to find the closest
+// color if X cannot allocate that color.
+
+// calculate what color is actually on the screen for a mask:
+static inline uchar realcolor(uchar color, uchar mask) {
+# if 0
+ // accurate version if the display has linear gamma, but fl_draw_image
+ // works better with the simpler version on most screens...
+ uchar m = mask;
+ uchar result = color&m;
+ for (;;) {
+ while (m&mask) {m>>=1; color>>=1;}
+ if (!m) break;
+ mask = m;
+ result |= color&m;
+ }
+ return result;
+# else
+ return (color&mask) | ( (~mask)&(mask>>1) );
+# endif
+}
+
+/**
+ Returns the X pixel number used to draw the given FLTK color index.
+ This is the X pixel that fl_color() would use.
+ \param[in] i color index
+ \return X pixel number
+*/
+ulong fl_xpixel(Fl_Color i) {
+ if (i & 0xffffff00) {
+ return fl_xpixel((i >> 24) & 255, (i >> 16) & 255, (i >> 8) & 255);
+ }
+
+ Fl_XColor &xmap = fl_xmap[fl_overlay][i];
+ if (xmap.mapped) return xmap.pixel;
+
+ if (!beenhere) figure_out_visual();
+
+ uchar r,g,b;
+ {unsigned c = fl_cmap[i]; r=uchar(c>>24); g=uchar(c>>16); b=uchar(c>>8);}
+
+# if USE_COLORMAP
+ Colormap colormap = fl_colormap;
+# if HAVE_OVERLAY
+ if (fl_overlay) colormap = fl_overlay_colormap; else
+# endif
+ if (fl_redmask) {
+# endif
+ // return color for a truecolor visual:
+ xmap.mapped = 2; // 2 prevents XFreeColor from being called
+ xmap.r = realcolor(r, fl_redmask);
+ xmap.g = realcolor(g, fl_greenmask);
+ xmap.b = realcolor(b, fl_bluemask);
+ return xmap.pixel =
+ (((r&fl_redmask) << fl_redshift)+
+ ((g&fl_greenmask)<<fl_greenshift)+
+ ((b&fl_bluemask)<< fl_blueshift)
+ ) >> fl_extrashift;
+# if USE_COLORMAP
+ }
+# if HAVE_OVERLAY
+ static XColor* ac[2];
+ XColor*& allcolors = ac[fl_overlay];
+ static int nc[2];
+ int& numcolors = nc[fl_overlay];
+# else
+ static XColor *allcolors;
+ static int numcolors;
+# endif
+
+ // I don't try to allocate colors with XAllocColor once it fails
+ // with any color. It is possible that it will work, since a color
+ // may have been freed, but some servers are extremely slow and this
+ // avoids one round trip:
+ if (!numcolors) { // don't try after a failure
+ XColor xcol;
+ xcol.red = r<<8; xcol.green = g<<8; xcol.blue = b<<8;
+ if (XAllocColor(fl_display, colormap, &xcol)) {
+ xmap.mapped = 1;
+ xmap.r = xcol.red>>8;
+ xmap.g = xcol.green>>8;
+ xmap.b = xcol.blue>>8;
+ return xmap.pixel = xcol.pixel;
+ }
+
+ // I only read the colormap once. Again this is due to the slowness
+ // of round-trips to the X server, even though other programs may alter
+ // the colormap after this and make decisions here wrong.
+# if HAVE_OVERLAY
+ if (fl_overlay) numcolors = fl_overlay_visual->colormap_size; else
+# endif
+ numcolors = fl_visual->colormap_size;
+ if (!allcolors) allcolors = new XColor[numcolors];
+ for (int p = numcolors; p--;) allcolors[p].pixel = p;
+ XQueryColors(fl_display, colormap, allcolors, numcolors);
+ }
+
+ // find least-squares match:
+ int mindist = 0x7FFFFFFF;
+ unsigned int bestmatch = 0;
+ for (unsigned int n = numcolors; n--;) {
+# if HAVE_OVERLAY
+ if (fl_overlay && n == fl_transparent_pixel) continue;
+# endif
+ XColor &a = allcolors[n];
+ int d, t;
+ t = int(r)-int(a.red>>8); d = t*t;
+ t = int(g)-int(a.green>>8); d += t*t;
+ t = int(b)-int(a.blue>>8); d += t*t;
+ if (d <= mindist) {bestmatch = n; mindist = d;}
+ }
+ XColor &p = allcolors[bestmatch];
+
+ // It appears to "work" to not call this XAllocColor, which will
+ // avoid another round-trip to the server. But then X does not
+ // know that this program "owns" this value, and can (and will)
+ // change it when the program that did allocate it exits:
+ if (XAllocColor(fl_display, colormap, &p)) {
+ xmap.mapped = 1;
+ xmap.pixel = p.pixel;
+ } else {
+ // However, if that XAllocColor fails, I have to give up and
+ // assume the pixel is ok for the duration of the program. This
+ // is due to bugs (?) in the Solaris X and some X terminals
+ // where XAllocColor *always* fails when the colormap is full,
+ // even if we ask for a color already in it...
+ xmap.mapped = 2; // 2 prevents XFreeColor from being called
+ xmap.pixel = bestmatch;
+ }
+ xmap.r = p.red>>8;
+ xmap.g = p.green>>8;
+ xmap.b = p.blue>>8;
+ return xmap.pixel;
+# endif
+}
+
+/**
+ Free color \p i if used, and clear mapping table entry.
+ \param[in] i color index
+ \param[in] overlay 0 for normal, 1 for overlay color
+*/
+void Fl::free_color(Fl_Color i, int overlay) {
+# if HAVE_OVERLAY
+# else
+ if (overlay) return;
+# endif
+ if (fl_xmap[overlay][i].mapped) {
+# if USE_COLORMAP
+# if HAVE_OVERLAY
+ Colormap colormap = overlay ? fl_overlay_colormap : fl_colormap;
+# else
+ Colormap colormap = fl_colormap;
+# endif
+ if (fl_xmap[overlay][i].mapped == 1)
+ XFreeColors(fl_display, colormap, &(fl_xmap[overlay][i].pixel), 1, 0);
+# endif
+ fl_xmap[overlay][i].mapped = 0;
+ }
+}
+
+/**
+ Set color mapping table entry \p i to color \p c
+ \param[in] i color index
+ \param[in] c color
+*/
+void Fl::set_color(Fl_Color i, unsigned c) {
+ if (fl_cmap[i] != c) {
+ free_color(i,0);
+# if HAVE_OVERLAY
+ free_color(i,1);
+# endif
+ fl_cmap[i] = c;
+ }
+}
+
+/**
+ @}
+ */
+
+//
+// End of "$Id$".
+//
diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_x.cxx b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_x.cxx
new file mode 100644
index 000000000..cec910f30
--- /dev/null
+++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_x.cxx
@@ -0,0 +1,676 @@
+//
+// "$Id$"
+//
+// X11 font utilities for the Fast Light Tool Kit (FLTK).
+//
+// Copyright 1998-2010 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:
+//
+// http://www.fltk.org/COPYING.php
+//
+// Please report all bugs and problems on the following page:
+//
+// http://www.fltk.org/str.php
+//
+
+// This function fills in the fltk font table with all the fonts that
+// are found on the X server. It tries to place the fonts into families
+// and to sort them so the first 4 in a family are normal, bold, italic,
+// and bold italic.
+
+// Standard X fonts are matched by a pattern that is always of
+// this form, and this pattern is put in the table:
+// "-*-family-weight-slant-width1-style-*-registry-encoding"
+
+// Non-standard font names (those not starting with '-') are matched
+// by a pattern of the form "prefix*suffix", where the '*' is where
+// fltk thinks the point size is, or by the actual font name if no
+// point size is found.
+
+// Fltk knows how to pull an "attribute" out of a font name, such as
+// bold or italic, by matching known x font field values. All words
+// that don't match a known attribute are combined into the "name"
+// of the font. Names are compared before attributes for sorting, this
+// makes the bold and plain version of a font come out next to each
+// other despite the poor X font naming scheme.
+
+// By default fl_set_fonts() only does iso8859-1 encoded fonts. You can
+// do all normal X fonts by passing "-*" or every possible font with "*".
+
+// Fl::set_font will take strings other than the ones this stores
+// and can identify any font on X that way. You may want to write your
+// own system of font management and not use this code.
+
+// turn word N of a X font name into either some attribute bits
+// (right now 0, FL_BOLD, or FL_ITALIC), or into -1 indicating that
+// the word should be put into the name:
+
+static int attribute(int n, const char *p) {
+ // don't put blank things into name:
+ if (!*p || *p=='-' || *p=='*') return 0;
+ if (n == 3) { // weight
+ if (!strncmp(p,"normal",6) ||
+ !strncmp(p,"light",5) ||
+ !strncmp(p,"medium",6) ||
+ !strncmp(p,"book",4)) return 0;
+ if (!strncmp(p,"bold",4) || !strncmp(p,"demi",4)) return FL_BOLD;
+ } else if (n == 4) { // slant
+ if (*p == 'r') return 0;
+ if (*p == 'i' || *p == 'o') return FL_ITALIC;
+ } else if (n == 5) { // sWidth
+ if (!strncmp(p,"normal",6)) return 0;
+ }
+ return -1;
+}
+
+// return non-zero if the registry-encoding should be used:
+extern const char* fl_encoding;
+static int use_registry(const char *p) {
+ return *p && *p!='*' && strcmp(p,fl_encoding);
+}
+
+// Bug: older versions calculated the value for *ap as a side effect of
+// making the name, and then forgot about it. To avoid having to change
+// the header files I decided to store this value in the last character
+// of the font name array.
+#define ENDOFBUFFER 127 // sizeof(Fl_Font.fontname)-1
+
+// turn a stored (with *'s) X font name into a pretty name:
+const char* Fl::get_font_name(Fl_Font fnum, int* ap) {
+ Fl_Fontdesc *f = fl_fonts + fnum;
+ if (!f->fontname[0]) {
+ int type = 0;
+ const char* p = f->name;
+ if (!p) {
+ if (ap) *ap = 0;
+ return "";
+ }
+ char *o = f->fontname;
+
+ if (*p != '-') { // non-standard font, just replace * with spaces:
+ if (strstr(p,"bold")) type = FL_BOLD;
+ if (strstr(p,"ital")) type |= FL_ITALIC;
+ for (;*p; p++) {
+ if (*p == '*' || *p == ' ' || *p == '-') {
+ do p++; while (*p == '*' || *p == ' ' || *p == '-');
+ if (!*p) break;
+ if (o < (f->fontname + ENDOFBUFFER - 1)) *o++ = ' ';
+ }
+ if (o < (f->fontname + ENDOFBUFFER - 1)) *o++ = *p;
+ }
+ *o = 0;
+
+ } else { // standard dash-separated font:
+
+ // get the family:
+ const char *x = fl_font_word(p,2); if (*x) x++; if (*x=='*') x++;
+ if (!*x) {
+ if (ap) *ap = 0;
+ return p;
+ }
+ const char *e = fl_font_word(x,1);
+ if ((e - x) < (int)(ENDOFBUFFER - 1)) {
+ // MRS: we want strncpy here, not strlcpy...
+ strncpy(o,x,e-x);
+ o += e-x;
+ } else {
+ strlcpy(f->fontname, x, ENDOFBUFFER);
+ o = f->fontname+ENDOFBUFFER-1;
+ }
+
+ // collect all the attribute words:
+ for (int n = 3; n <= 6; n++) {
+ // get the next word:
+ if (*e) e++; x = e; e = fl_font_word(x,1);
+ int t = attribute(n,x);
+ if (t < 0) {
+ if (o < (f->fontname + ENDOFBUFFER - 1)) *o++ = ' ';
+ if ((e - x) < (int)(ENDOFBUFFER - (o - f->fontname) - 1)) {
+ // MRS: we want strncpy here, not strlcpy...
+ strncpy(o,x,e-x);
+ o += e-x;
+ } else {
+ strlcpy(o,x, ENDOFBUFFER - (o - f->fontname) - 1);
+ o = f->fontname+ENDOFBUFFER-1;
+ }
+ } else type |= t;
+ }
+
+ // skip over the '*' for the size and get the registry-encoding:
+ x = fl_font_word(e,2);
+ if (*x) {x++; *o++ = '('; while (*x) *o++ = *x++; *o++ = ')';}
+
+ *o = 0;
+ if (type & FL_BOLD) strlcat(f->fontname, " bold", ENDOFBUFFER);
+ if (type & FL_ITALIC) strlcat(f->fontname, " italic", ENDOFBUFFER);
+ }
+ f->fontname[ENDOFBUFFER] = (char)type;
+ }
+ if (ap) *ap = f->fontname[ENDOFBUFFER];
+ return f->fontname;
+}
+
+extern "C" {
+// sort raw (non-'*') X font names into perfect order:
+
+static int ultrasort(const void *aa, const void *bb) {
+ const char *a = *(char **)aa;
+ const char *b = *(char **)bb;
+
+ // sort all non x-fonts at the end:
+ if (*a != '-') {
+ if (*b == '-') return 1;
+ // 2 non-x fonts are matched by "numeric sort"
+ int ret = 0;
+ for (;;) {
+ if (isdigit(*a) && isdigit(*b)) {
+ int na = strtol(a, (char **)&a, 10);
+ int nb = strtol(b, (char **)&b, 10);
+ if (!ret) ret = na-nb;
+ } else if (*a != *b) {
+ return (*a-*b);
+ } else if (!*a) {
+ return ret;
+ } else {
+ a++; b++;
+ }
+ }
+ } else {
+ if (*b != '-') return -1;
+ }
+
+ // skip the foundry (assume equal):
+ for (a++; *a && *a++!='-';);
+ for (b++; *b && *b++!='-';);
+
+ // compare the family and all the attribute words:
+ int atype = 0;
+ int btype = 0;
+ for (int n = 2; n <= 6; n++) {
+ int at = attribute(n,a);
+ int bt = attribute(n,b);
+ if (at < 0) {
+ if (bt >= 0) return 1;
+ for (;;) {if (*a!=*b) return *a-*b; b++; if (!*a || *a++=='-') break;}
+ } else {
+ if (bt < 0) return -1;
+ a = fl_font_word(a,1); if (*a) a++;
+ b = fl_font_word(b,1); if (*b) b++;
+ atype |= at; btype |= bt;
+ }
+ }
+
+ // remember the pixel size:
+ int asize = atoi(a);
+ int bsize = atoi(b);
+
+ // compare the registry/encoding:
+ a = fl_font_word(a,6); if (*a) a++;
+ b = fl_font_word(b,6); if (*b) b++;
+ if (use_registry(a)) {
+ if (!use_registry(b)) return 1;
+ int r = strcmp(a,b); if (r) return r;
+ } else {
+ if (use_registry(b)) return -1;
+ }
+
+ if (atype != btype) return atype-btype;
+ if (asize != bsize) return asize-bsize;
+
+ // something wrong, just do a string compare...
+ return strcmp(*(char**)aa, *(char**)bb);
+}
+}
+
+// converts a X font name to a standard starname, returns point size:
+static int to_canonical(char *to, const char *from, size_t tolen) {
+ char* c = fl_find_fontsize((char*)from);
+ if (!c) return -1; // no point size found...
+ const char* endptr;
+ int size = strtol(c,(char**)&endptr,10);
+ if (from[0] == '-') {
+ // replace the "foundry" with -*-:
+ *to++ = '-'; *to++ = '*';
+ for (from++; *from && *from != '-'; from++);
+ // skip to the registry-encoding:
+ endptr = (char*)fl_font_word(endptr,6);
+ if (*endptr && !use_registry(endptr+1)) endptr = "";
+ }
+ int n = c-from;
+ // MRS: we want strncpy here, not strlcpy...
+ if (n > (int)(tolen - 1)) return -1;
+ strncpy(to,from,n);
+ to[n++] = '*';
+ strlcpy(to+n,endptr, tolen - n);
+ return size;
+}
+
+static unsigned int fl_free_font = FL_FREE_FONT;
+
+Fl_Font Fl::set_fonts(const char* xstarname) {
+ if (fl_free_font > (unsigned)FL_FREE_FONT) // already been here
+ return (Fl_Font)fl_free_font;
+ fl_open_display();
+ int xlistsize;
+ char buf[20];
+ if (!xstarname) {
+ strcpy(buf,"-*-"); strcpy(buf+3,fl_encoding);
+ xstarname = buf;
+ }
+ char **xlist = XListFonts(fl_display, xstarname, 10000, &xlistsize);
+ if (!xlist) return (Fl_Font)fl_free_font;
+ qsort(xlist, xlistsize, sizeof(*xlist), ultrasort);
+ int used_xlist = 0;
+ for (int i=0; i<xlistsize;) {
+ int first_xlist = i;
+ const char *p = xlist[i++];
+ char canon[1024];
+ int size = to_canonical(canon, p, sizeof(canon));
+ if (size >= 0) {
+ for (;;) { // find all matching fonts:
+ if (i >= xlistsize) break;
+ const char *q = xlist[i];
+ char this_canon[1024];
+ if (to_canonical(this_canon, q, sizeof(this_canon)) < 0) break;
+ if (strcmp(canon, this_canon)) break;
+ i++;
+ }
+ /*if (*p=='-' || i > first_xlist+1)*/ p = canon;
+ }
+ unsigned int j;
+ for (j = 0;; j++) {
+ /*if (j < FL_FREE_FONT) {
+ // see if it is one of our built-in fonts:
+ // if so, set the list of x fonts, since we have it anyway
+ if (fl_fonts[j].name && !strcmp(fl_fonts[j].name, p)) break;
+ } else */{
+ j = fl_free_font++;
+ if (p == canon) p = strdup(p); else used_xlist = 1;
+ Fl::set_font((Fl_Font)j, p);
+ break;
+ }
+ }
+ if (!fl_fonts[j].xlist) {
+ fl_fonts[j].xlist = xlist+first_xlist;
+ fl_fonts[j].n = -(i-first_xlist);
+ used_xlist = 1;
+ }
+ }
+ if (!used_xlist) XFreeFontNames(xlist);
+ return (Fl_Font)fl_free_font;
+}
+
+int Fl::get_font_sizes(Fl_Font fnum, int*& sizep) {
+ Fl_Fontdesc *s = fl_fonts+fnum;
+ if (!s->name) s = fl_fonts; // empty slot in table, use entry 0
+ if (!s->xlist) {
+ fl_open_display();
+ s->xlist = XListFonts(fl_display, s->name, 100, &(s->n));
+ if (!s->xlist) return 0;
+ }
+ int listsize = s->n; if (listsize<0) listsize = -listsize;
+ static int sizes[128];
+ int numsizes = 0;
+ for (int i = 0; i < listsize; i++) {
+ char *q = s->xlist[i];
+ char *d = fl_find_fontsize(q);
+ if (!d) continue;
+ int s = strtol(d,0,10);
+ if (!numsizes || sizes[numsizes-1] < s) {
+ sizes[numsizes++] = s;
+ } else {
+ // insert-sort the new size into list:
+ int n;
+ for (n = numsizes-1; n > 0; n--) if (sizes[n-1] < s) break;
+ if (sizes[n] != s) {
+ for (int m = numsizes; m > n; m--) sizes[m] = sizes[m-1];
+ sizes[n] = s;
+ numsizes++;
+ }
+ }
+ }
+ sizep = sizes;
+ return numsizes;
+}
+
+//
+// End of "$Id$".
+//
+//
+// "$Id$"
+//
+// Standard X11 font selection code for the Fast Light Tool Kit (FLTK).
+//
+// Copyright 1998-2011 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:
+//
+// http://www.fltk.org/COPYING.php
+//
+// Please report all bugs and problems on the following page:
+//
+// http://www.fltk.org/str.php
+//
+#ifndef FL_DOXYGEN
+
+Fl_Font_Descriptor::Fl_Font_Descriptor(const char* name) {
+ font = XCreateUtf8FontStruct(fl_display, name);
+ if (!font) {
+ Fl::warning("bad font: %s", name);
+ font = XCreateUtf8FontStruct(fl_display, "fixed");
+ }
+# if HAVE_GL
+ listbase = 0;
+ for (int u = 0; u < 64; u++) glok[u] = 0;
+# endif
+}
+
+Fl_XFont_On_Demand fl_xfont;
+
+Fl_Font_Descriptor::~Fl_Font_Descriptor() {
+# if HAVE_GL
+// Delete list created by gl_draw(). This is not done by this code
+// as it will link in GL unnecessarily. There should be some kind
+// of "free" routine pointer, or a subclass?
+// if (listbase) {
+// int base = font->min_char_or_byte2;
+// int size = font->max_char_or_byte2-base+1;
+// int base = 0; int size = 256;
+// glDeleteLists(listbase+base,size);
+// }
+# endif
+ if (this == fl_graphics_driver->font_descriptor()) {
+ fl_graphics_driver->font_descriptor(NULL);
+ fl_xfont = 0;
+ }
+ XFreeUtf8FontStruct(fl_display, font);
+}
+
+////////////////////////////////////////////////////////////////
+
+// WARNING: if you add to this table, you must redefine FL_FREE_FONT
+// in Enumerations.H & recompile!!
+static Fl_Fontdesc built_in_table[] = {
+{"-*-helvetica-medium-r-normal--*"},
+{"-*-helvetica-bold-r-normal--*"},
+{"-*-helvetica-medium-o-normal--*"},
+{"-*-helvetica-bold-o-normal--*"},
+{"-*-courier-medium-r-normal--*"},
+{"-*-courier-bold-r-normal--*"},
+{"-*-courier-medium-o-normal--*"},
+{"-*-courier-bold-o-normal--*"},
+{"-*-times-medium-r-normal--*"},
+{"-*-times-bold-r-normal--*"},
+{"-*-times-medium-i-normal--*"},
+{"-*-times-bold-i-normal--*"},
+{"-*-symbol-*"},
+{"-*-lucidatypewriter-medium-r-normal-sans-*"},
+{"-*-lucidatypewriter-bold-r-normal-sans-*"},
+{"-*-*zapf dingbats-*"}
+};
+
+Fl_Fontdesc* fl_fonts = built_in_table;
+
+#define MAXSIZE 32767
+
+// return dash number N, or pointer to ending null if none:
+const char* fl_font_word(const char* p, int n) {
+ while (*p) {if (*p=='-') {if (!--n) break;} p++;}
+ return p;
+}
+
+// return a pointer to a number we think is "point size":
+char* fl_find_fontsize(char* name) {
+ char* c = name;
+ // for standard x font names, try after 7th dash:
+ if (*c == '-') {
+ c = (char*)fl_font_word(c,7);
+ if (*c++ && isdigit(*c)) return c;
+ return 0; // malformed x font name?
+ }
+ char* r = 0;
+ // find last set of digits:
+ for (c++;* c; c++)
+ if (isdigit(*c) && !isdigit(*(c-1))) r = c;
+ return r;
+}
+
+//const char* fl_encoding = "iso8859-1";
+const char* fl_encoding = "iso10646-1";
+
+// return true if this matches fl_encoding:
+int fl_correct_encoding(const char* name) {
+ if (*name != '-') return 0;
+ const char* c = fl_font_word(name,13);
+ return (*c++ && !strcmp(c,fl_encoding));
+}
+
+static const char *find_best_font(const char *fname, int size) {
+ int cnt;
+ static char **list = NULL;
+// locate or create an Fl_Font_Descriptor for a given Fl_Fontdesc and size:
+ if (list) XFreeFontNames(list);
+ list = XListFonts(fl_display, fname, 100, &cnt);
+ if (!list) return "fixed";
+
+ // search for largest <= font size:
+ char* name = list[0]; int ptsize = 0; // best one found so far
+ int matchedlength = 32767;
+ char namebuffer[1024]; // holds scalable font name
+ int found_encoding = 0;
+ int m = cnt; if (m<0) m = -m;
+ for (int n=0; n < m; n++) {
+ char* thisname = list[n];
+ if (fl_correct_encoding(thisname)) {
+ if (!found_encoding) ptsize = 0; // force it to choose this
+ found_encoding = 1;
+ } else {
+ if (found_encoding) continue;
+ }
+ char* c = (char*)fl_find_fontsize(thisname);
+ int thissize = c ? atoi(c) : MAXSIZE;
+ int thislength = strlen(thisname);
+ if (thissize == size && thislength < matchedlength) {
+ // exact match, use it:
+ name = thisname;
+ ptsize = size;
+ matchedlength = thislength;
+ } else if (!thissize && ptsize!=size) {
+ // whoa! A scalable font! Use unless exact match found:
+ int l = c-thisname;
+ memcpy(namebuffer,thisname,l);
+ l += sprintf(namebuffer+l,"%d",size);
+ while (*c == '0') c++;
+ strcpy(namebuffer+l,c);
+ name = namebuffer;
+ ptsize = size;
+ } else if (!ptsize || // no fonts yet
+ (thissize < ptsize && ptsize > size) || // current font too big
+ (thissize > ptsize && thissize <= size) // current too small
+ ) {
+ name = thisname;
+ ptsize = thissize;
+ matchedlength = thislength;
+ }
+ }
+
+// if (ptsize != size) { // see if we already found this unscalable font:
+// for (f = s->first; f; f = f->next) {
+// if (f->minsize <= ptsize && f->maxsize >= ptsize) {
+// if (f->minsize > size) f->minsize = size;
+// if (f->maxsize < size) f->maxsize = size;
+// return f;
+// }
+// }
+// }
+//
+// // okay, we definately have some name, make the font:
+// f = new Fl_Font_Descriptor(name);
+// if (ptsize < size) {f->minsize = ptsize; f->maxsize = size;}
+// else {f->minsize = size; f->maxsize = ptsize;}
+// f->next = s->first;
+// s->first = f;
+// return f;
+
+ return name;
+}
+
+static char *put_font_size(const char *n, int size)
+{
+ int i = 0;
+ char *buf;
+ const char *ptr;
+ const char *f;
+ char *name;
+ int nbf = 1;
+ name = strdup(n);
+ while (name[i]) {
+ if (name[i] == ',') {nbf++; name[i] = '\0';}
+ i++;
+ }
+
+ buf = (char*) malloc(nbf * 256);
+ buf[0] = '\0';
+ ptr = name;
+ i = 0;
+ while (ptr && nbf > 0) {
+ f = find_best_font(ptr, size);
+ while (*f) {
+ buf[i] = *f;
+ f++; i++;
+ }
+ nbf--;
+ while (*ptr) ptr++;
+ if (nbf) {
+ ptr++;
+ buf[i] = ',';
+ i++;
+ }
+ while(isspace(*ptr)) ptr++;
+ }
+ buf[i] = '\0';
+ free(name);
+ return buf;
+}
+
+
+char *fl_get_font_xfld(int fnum, int size) {
+ Fl_Fontdesc* s = fl_fonts+fnum;
+ if (!s->name) s = fl_fonts; // use font 0 if still undefined
+ fl_open_display();
+ return put_font_size(s->name, size);
+}
+
+// locate or create an Fl_Font_Descriptor for a given Fl_Fontdesc and size:
+static Fl_Font_Descriptor* find(int fnum, int size) {
+ char *name;
+ Fl_Fontdesc* s = fl_fonts+fnum;
+ if (!s->name) s = fl_fonts; // use font 0 if still undefined
+ Fl_Font_Descriptor* f;
+ for (f = s->first; f; f = f->next)
+ if (f->size == size) return f;
+ fl_open_display();
+
+ name = put_font_size(s->name, size);
+ f = new Fl_Font_Descriptor(name);
+ f->size = size;
+ f->next = s->first;
+ s->first = f;
+ free(name);
+ return f;
+}
+
+
+////////////////////////////////////////////////////////////////
+// Public interface:
+
+void *fl_xftfont = 0;
+static GC font_gc;
+
+XFontStruct* Fl_XFont_On_Demand::value() {
+ return ptr;
+}
+
+void Fl_Xlib_Graphics_Driver::font(Fl_Font fnum, Fl_Fontsize size) {
+ if (fnum==-1) {
+ Fl_Graphics_Driver::font(0, 0);
+ return;
+ }
+ if (fnum == Fl_Graphics_Driver::font() && size == Fl_Graphics_Driver::size()) return;
+ Fl_Graphics_Driver::font(fnum, size);
+ Fl_Font_Descriptor* f = find(fnum, size);
+ if (f != this->font_descriptor()) {
+ this->font_descriptor(f);
+ fl_xfont = f->font->fonts[0];
+ font_gc = 0;
+ }
+}
+
+int Fl_Xlib_Graphics_Driver::height() {
+ if (font_descriptor()) return font_descriptor()->font->ascent + font_descriptor()->font->descent;
+ else return -1;
+}
+
+int Fl_Xlib_Graphics_Driver::descent() {
+ if (font_descriptor()) return font_descriptor()->font->descent;
+ else return -1;
+}
+
+double Fl_Xlib_Graphics_Driver::width(const char* c, int n) {
+ if (font_descriptor()) return (double) XUtf8TextWidth(font_descriptor()->font, c, n);
+ else return -1;
+}
+
+double Fl_Xlib_Graphics_Driver::width(unsigned int c) {
+ if (font_descriptor()) return (double) XUtf8UcsWidth(font_descriptor()->font, c);
+ else return -1;
+}
+
+void Fl_Xlib_Graphics_Driver::text_extents(const char *c, int n, int &dx, int &dy, int &W, int &H) {
+ if (font_gc != fl_gc) {
+ if (!font_descriptor()) font(FL_HELVETICA, FL_NORMAL_SIZE);
+ font_gc = fl_gc;
+ XSetFont(fl_display, fl_gc, font_descriptor()->font->fid);
+ }
+ int xx, yy, ww, hh;
+ xx = yy = ww = hh = 0;
+ if (fl_gc) XUtf8_measure_extents(fl_display, fl_window, font_descriptor()->font, fl_gc, &xx, &yy, &ww, &hh, c, n);
+
+ W = ww; H = hh; dx = xx; dy = yy;
+// This is the safe but mostly wrong thing we used to do...
+// W = 0; H = 0;
+// fl_measure(c, W, H, 0);
+// dx = 0;
+// dy = fl_descent() - H;
+}
+
+void Fl_Xlib_Graphics_Driver::draw(const char* c, int n, int x, int y) {
+ if (font_gc != fl_gc) {
+ if (!font_descriptor()) this->font(FL_HELVETICA, FL_NORMAL_SIZE);
+ font_gc = fl_gc;
+ XSetFont(fl_display, fl_gc, font_descriptor()->font->fid);
+ }
+ if (fl_gc) XUtf8DrawString(fl_display, fl_window, font_descriptor()->font, fl_gc, x, y, c, n);
+}
+
+void Fl_Xlib_Graphics_Driver::draw(int angle, const char *str, int n, int x, int y) {
+ fprintf(stderr,"ROTATING TEXT NOT IMPLEMENTED\n");
+ this->draw(str, n, (int)x, (int)y);
+}
+
+void Fl_Xlib_Graphics_Driver::rtl_draw(const char* c, int n, int x, int y) {
+ if (font_gc != fl_gc) {
+ if (!font_descriptor()) this->font(FL_HELVETICA, FL_NORMAL_SIZE);
+ font_gc = fl_gc;
+ }
+ if (fl_gc) XUtf8DrawRtlString(fl_display, fl_window, font_descriptor()->font, fl_gc, x, y, c, n);
+}
+#endif // FL_DOXYGEN
+//
+// End of "$Id$".
+//
diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx
new file mode 100644
index 000000000..91ee460ce
--- /dev/null
+++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx
@@ -0,0 +1,1081 @@
+//
+// "$Id$"
+//
+// More font utilities for the Fast Light Tool Kit (FLTK).
+//
+// Copyright 1998-2011 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:
+//
+// http://www.fltk.org/COPYING.php
+//
+// Please report all bugs and problems on the following page:
+//
+// http://www.fltk.org/str.php
+//
+
+#include <X11/Xft/Xft.h>
+
+// This function fills in the fltk font table with all the fonts that
+// are found on the X server. It tries to place the fonts into families
+// and to sort them so the first 4 in a family are normal, bold, italic,
+// and bold italic.
+
+// Bug: older versions calculated the value for *ap as a side effect of
+// making the name, and then forgot about it. To avoid having to change
+// the header files I decided to store this value in the last character
+// of the font name array.
+#define ENDOFBUFFER 127 // sizeof(Fl_Font.fontname)-1
+
+// turn a stored font name in "fltk format" into a pretty name:
+const char* Fl::get_font_name(Fl_Font fnum, int* ap) {
+ Fl_Fontdesc *f = fl_fonts + fnum;
+ if (!f->fontname[0]) {
+ const char* p = f->name;
+ int type;
+ switch (p[0]) {
+ case 'B': type = FL_BOLD; break;
+ case 'I': type = FL_ITALIC; break;
+ case 'P': type = FL_BOLD | FL_ITALIC; break;
+ default: type = 0; break;
+ }
+
+ // NOTE: This can cause duplications in fonts that already have Bold or Italic in
+ // their "name". Maybe we need to find a cleverer way?
+ strlcpy(f->fontname, p+1, ENDOFBUFFER);
+ if (type & FL_BOLD) strlcat(f->fontname, " bold", ENDOFBUFFER);
+ if (type & FL_ITALIC) strlcat(f->fontname, " italic", ENDOFBUFFER);
+ f->fontname[ENDOFBUFFER] = (char)type;
+ }
+ if (ap) *ap = f->fontname[ENDOFBUFFER];
+ return f->fontname;
+}
+
+///////////////////////////////////////////////////////////
+#define LOCAL_RAW_NAME_MAX 256
+
+extern "C" {
+// sort returned fontconfig font names
+static int name_sort(const void *aa, const void *bb) {
+ // What should we do here? Just do a string compare for now...
+ // NOTE: This yeilds some oddities - in particular a Blah Bold font will be
+ // listed before Blah...
+ // Also - the fontconfig listing returns some faces that are effectively duplicates
+ // as far as fltk is concerned, e.g. where there are ko or ja variants that we
+ // can't distinguish (since we are not yet fully UTF-*) - should we strip them here?
+ return fl_ascii_strcasecmp(*(char**)aa, *(char**)bb);
+} // end of name_sort
+} // end of extern C section
+
+
+// Read the "pretty" name we have derived from fontconfig then convert
+// it into the format fltk uses internally for Xft names...
+// This is just a mess - I should have tokenised the strings and gone from there,
+// but I really thought this would be easier!
+static void make_raw_name(char *raw, char *pretty)
+{
+ // Input name will be "Some Name:style = Bold Italic" or whatever
+ // The plan is this:
+ // - the first char in the "raw" name becomes either I, B, P or " " for
+ // italic, bold, bold italic or normal - this seems to be the fltk way...
+
+ char *style = strchr(pretty, ':');
+
+ if (style)
+ {
+ *style = 0; // Terminate "name" string
+ style ++; // point to start of style section
+ }
+
+ // It is still possible that the "pretty" name has multiple comma separated entries
+ // I've seen this often in CJK fonts, for example... Keep only the first one... This
+ // is not ideal, the CJK fonts often have the name in utf8 in several languages. What
+ // we ought to do is use fontconfig to query the available languages and pick one... But which?
+#if 0 // loop to keep the LAST name entry...
+ char *nm1 = pretty;
+ char *nm2 = strchr(nm1, ',');
+ while(nm2) {
+ nm1 = nm2 + 1;
+ nm2 = strchr(nm1, ',');
+ }
+ raw[0] = ' '; raw[1] = 0; // Default start of "raw name" text
+ strncat(raw, nm1, LOCAL_RAW_NAME_MAX-1); // only copy MAX-1 chars, we have already set cell 0
+ // Ensure raw is terminated, just in case the given name is infeasibly long...
+ raw[LOCAL_RAW_NAME_MAX-1] = 0;
+#else // keep the first remaining name entry
+ char *nm2 = strchr(pretty, ',');
+ if(nm2) *nm2 = 0; // terminate name after first entry
+ raw[0] = ' '; raw[1] = 0; // Default start of "raw name" text
+ strncat(raw, pretty, LOCAL_RAW_NAME_MAX-1); // only copy MAX-1 chars, we have already set cell 0
+ // Ensure raw is terminated, just in case the given name is infeasibly long...
+ raw[LOCAL_RAW_NAME_MAX-1] = 0;
+#endif
+ // At this point, the name is "marked" as regular...
+ if (style)
+ {
+#define PLAIN 0
+#define BOLD 1
+#define ITALIC 2
+#define BITALIC (BOLD | ITALIC)
+
+ int mods = PLAIN;
+ char *last = style + strlen(style) - 2;
+
+ // Now try and parse the style string - look for the "=" sign
+ style = strchr(style, '=');
+ while ((style) && (style < last))
+ {
+ int type;
+ while ((*style == '=') || (*style == ' ') || (*style == '\t') || (*style == ','))
+ {
+ style++; // Start of Style string
+ if ((style >= last) || (*style == 0)) continue;
+ }
+ type = toupper(style[0]);
+ switch (type)
+ {
+ // Things we might see: Regular Normal Bold Italic Oblique (??what??) Medium
+ // Roman Light Demi Sans SemiCondensed SuperBold Book... etc...
+ // Things we actually care about: Bold Italic Oblique SuperBold - Others???
+ case 'I':
+ if (strncasecmp(style, "Italic", 6) == 0)
+ {
+ mods |= ITALIC;
+ }
+ goto NEXT_STYLE;
+
+ case 'B':
+ if (strncasecmp(style, "Bold", 4) == 0)
+ {
+ mods |= BOLD;
+ }
+ goto NEXT_STYLE;
+
+ case 'O':
+ if (strncasecmp(style, "Oblique", 7) == 0)
+ {
+ mods |= ITALIC;
+ }
+ goto NEXT_STYLE;
+
+ case 'S':
+ if (strncasecmp(style, "SuperBold", 9) == 0)
+ {
+ mods |= BOLD;
+ }
+ goto NEXT_STYLE;
+
+ default: // find the next gap
+ goto NEXT_STYLE;
+ } // switch end
+NEXT_STYLE:
+ while ((*style != ' ') && (*style != '\t') && (*style != ','))
+ {
+ style++;
+ if ((style >= last) || (*style == 0)) goto STYLE_DONE;
+ }
+ }
+STYLE_DONE:
+ // Set the "modifier" character in the raw string
+ switch(mods)
+ {
+ case BOLD: raw[0] = 'B';
+ break;
+ case ITALIC: raw[0] = 'I';
+ break;
+ case BITALIC: raw[0] = 'P';
+ break;
+ default: raw[0] = ' ';
+ break;
+ }
+ }
+} // make_raw_name
+
+///////////////////////////////////////////////////////////
+
+static int fl_free_font = FL_FREE_FONT;
+
+// Uses the fontconfig lib to construct a list of all installed fonts.
+// I tried using XftListFonts for this, but the API is tricky - and when
+// I looked at the XftList* code, it calls the Fc* functions anyway, so...
+//
+// Also, for now I'm ignoring the "pattern_name" and just getting everything...
+// AND I don't try and skip the fonts we've already loaded in the defaults.
+// Blimey! What a hack!
+Fl_Font Fl::set_fonts(const char* pattern_name)
+{
+ FcFontSet *fnt_set; // Will hold the list of fonts we find
+ FcPattern *fnt_pattern; // Holds the generic "match all names" pattern
+ FcObjectSet *fnt_obj_set = 0; // Holds the generic "match all objects"
+
+ int j; // loop iterator variable
+ int font_count; // Total number of fonts found to process
+ char **full_list; // The list of font names we build
+
+ if (fl_free_font > FL_FREE_FONT) // already been here
+ return (Fl_Font)fl_free_font;
+
+ fl_open_display(); // Just in case...
+
+ // Make sure fontconfig is ready... is this necessary? The docs say it is
+ // safe to call it multiple times, so just go for it anyway!
+ if (!FcInit())
+ {
+ // What to do? Just return defaults...
+ return FL_FREE_FONT;
+ }
+
+ // Create a search pattern that will match every font name - I think this
+ // does the Right Thing, but am not certain...
+ //
+ // This could possibly be "enhanced" to pay attention to the requested
+ // "pattern_name"?
+ fnt_pattern = FcPatternCreate();
+ fnt_obj_set = FcObjectSetBuild(FC_FAMILY, FC_STYLE, (void *)0);
+
+ // Hopefully, this is a set of all the fonts...
+ fnt_set = FcFontList(0, fnt_pattern, fnt_obj_set);
+
+ // We don't need the fnt_pattern and fnt_obj_set any more, release them
+ FcPatternDestroy(fnt_pattern);
+ FcObjectSetDestroy(fnt_obj_set);
+
+ // Now, if we got any fonts, iterate through them...
+ if (fnt_set)
+ {
+ char *stop;
+ char *start;
+ char *first;
+
+ font_count = fnt_set->nfont; // How many fonts?
+
+ // Allocate array of char*'s to hold the name strings
+ full_list = (char **)malloc(sizeof(char *) * font_count);
+
+ // iterate through all the font patterns and get the names out...
+ for (j = 0; j < font_count; j++)
+ {
+ // NOTE: FcChar8 is a typedef of "unsigned char"...
+ FcChar8 *font; // String to hold the font's name
+
+ // Convert from fontconfig internal pattern to human readable name
+ // NOTE: This WILL malloc storage, so we need to free it later...
+ font = FcNameUnparse(fnt_set->fonts[j]);
+
+ // The returned strings look like this...
+ // Century Schoolbook:style=Bold Italic,fed kursiv,Fett Kursiv,...
+ // So the bit we want is up to the first comma - BUT some strings have
+ // more than one name, separated by, guess what?, a comma...
+ stop = start = first = 0;
+ stop = strchr((char *)font, ',');
+ start = strchr((char *)font, ':');
+ if ((stop) && (start) && (stop < start))
+ {
+ first = stop + 1; // discard first version of name
+ // find first comma *after* the end of the name
+ stop = strchr((char *)start, ',');
+ }
+ else
+ {
+ first = (char *)font; // name is just what was returned
+ }
+ // Truncate the name after the (english) modifiers description
+ // Matt: Actually, there is no guarantee that the *first* description is the English one.
+ // Matt: So we keep the entire description, just in case.
+ //if (stop)
+ //{
+ // *stop = 0; // Terminate the string at the first comma, if there is one
+ //}
+
+ // Copy the font description into our list
+ if (first == (char *)font)
+ { // The listed name is still OK
+ full_list[j] = (char *)font;
+ }
+ else
+ { // The listed name has been modified
+ full_list[j] = strdup(first);
+ // Free the font name storage
+ free (font);
+ }
+ // replace "style=Regular" so strcmp sorts it first
+ if (start) {
+ char *reg = strstr(full_list[j], "=Regular");
+ if (reg) reg[1]='.';
+ }
+ }
+
+ // Release the fnt_set - we don't need it any more
+ FcFontSetDestroy(fnt_set);
+
+ // Sort the list into alphabetic order
+ qsort(full_list, font_count, sizeof(*full_list), name_sort);
+
+ // Now let us add the names we got to fltk's font list...
+ for (j = 0; j < font_count; j++)
+ {
+ if (full_list[j])
+ {
+ char xft_name[LOCAL_RAW_NAME_MAX];
+ char *stored_name;
+ // Parse the strings into FLTK-XFT style..
+ make_raw_name(xft_name, full_list[j]);
+ // NOTE: This just adds on AFTER the default fonts - no attempt is made
+ // to identify already loaded fonts. Is this bad?
+ stored_name = strdup(xft_name);
+ Fl::set_font((Fl_Font)(j + FL_FREE_FONT), stored_name);
+ fl_free_font ++;
+
+ free(full_list[j]); // release that name from our internal array
+ }
+ }
+ // Now we are done with the list, release it fully
+ free(full_list);
+ }
+ return (Fl_Font)fl_free_font;
+} // ::set_fonts
+////////////////////////////////////////////////////////////////
+
+
+extern "C" {
+static int int_sort(const void *aa, const void *bb) {
+ return (*(int*)aa)-(*(int*)bb);
+}
+}
+
+////////////////////////////////////////////////////////////////
+
+// Return all the point sizes supported by this font:
+// Suprisingly enough Xft works exactly like fltk does and returns
+// the same list. Except there is no way to tell if the font is scalable.
+int Fl::get_font_sizes(Fl_Font fnum, int*& sizep) {
+ Fl_Fontdesc *s = fl_fonts+fnum;
+ if (!s->name) s = fl_fonts; // empty slot in table, use entry 0
+
+ fl_open_display();
+ XftFontSet* fs = XftListFonts(fl_display, fl_screen,
+ XFT_FAMILY, XftTypeString, s->name+1,
+ (void *)0,
+ XFT_PIXEL_SIZE,
+ (void *)0);
+ static int* array = 0;
+ static int array_size = 0;
+ if (fs->nfont >= array_size) {
+ delete[] array;
+ array = new int[array_size = fs->nfont+1];
+ }
+ array[0] = 0; int j = 1; // claim all fonts are scalable
+ for (int i = 0; i < fs->nfont; i++) {
+ double v;
+ if (XftPatternGetDouble(fs->fonts[i], XFT_PIXEL_SIZE, 0, &v) == XftResultMatch) {
+ array[j++] = int(v);
+ }
+ }
+ qsort(array+1, j-1, sizeof(int), int_sort);
+ XftFontSetDestroy(fs);
+ sizep = array;
+ return j;
+}
+
+//
+// End of "$Id$".
+//
+//
+// "$Id$"
+//
+// Xft font code for the Fast Light Tool Kit (FLTK).
+//
+// Copyright 2001-2011 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:
+//
+// http://www.fltk.org/COPYING.php
+//
+// Please report all bugs and problems on the following page:
+//
+// http://www.fltk.org/str.php
+//
+
+//
+// Draw fonts using Keith Packard's Xft library to provide anti-
+// aliased text. Yow!
+//
+// Many thanks to Carl for making the original version of this.
+//
+// This font code only requires libXft to work. Contrary to popular
+// belief there is no need to have FreeType, or the Xrender extension
+// available to use this code. You will just get normal Xlib fonts
+// (Xft calls them "core" fonts) The Xft algorithms for choosing
+// these is about as good as the FLTK ones (I hope to fix it so it is
+// exactly as good...), plus it can cache its results and share them
+// between programs, so using this should be a win in all cases. Also
+// it should be obvious by comparing this file and fl_font_x.cxx that
+// it is a lot easier to program with Xft than with Xlib.
+//
+// Also, Xft supports UTF-8 text rendering directly, which will allow
+// us to support UTF-8 on all platforms more easily.
+//
+// To actually get antialiasing you need the following:
+//
+// 1. You have XFree86 4
+// 2. You have the XRender extension
+// 3. Your X device driver supports the render extension
+// 4. You have libXft
+// 5. Your libXft has FreeType2 support compiled in
+// 6. You have the FreeType2 library
+//
+// Distributions that have XFree86 4.0.3 or later should have all of this...
+//
+// Unlike some other Xft packages, I tried to keep this simple and not
+// to work around the current problems in Xft by making the "patterns"
+// complicated. I believe doing this defeats our ability to improve Xft
+// itself. You should edit the ~/.xftconfig file to "fix" things, there
+// are several web pages of information on how to do this.
+//
+#ifndef FL_DOXYGEN
+
+#include <X11/Xft/Xft.h>
+
+#include <math.h>
+
+// The predefined fonts that FLTK has:
+static Fl_Fontdesc built_in_table[] = {
+#if 1
+{" sans"},
+{"Bsans"},
+{"Isans"},
+{"Psans"},
+{" mono"},
+{"Bmono"},
+{"Imono"},
+{"Pmono"},
+{" serif"},
+{"Bserif"},
+{"Iserif"},
+{"Pserif"},
+{" symbol"},
+{" screen"},
+{"Bscreen"},
+{" zapf dingbats"},
+#else
+{" helvetica"},
+{"Bhelvetica"},
+{"Ihelvetica"},
+{"Phelvetica"},
+{" courier"},
+{"Bcourier"},
+{"Icourier"},
+{"Pcourier"},
+{" times"},
+{"Btimes"},
+{"Itimes"},
+{"Ptimes"},
+{" symbol"},
+{" lucidatypewriter"},
+{"Blucidatypewriter"},
+{" zapf dingbats"},
+#endif
+};
+
+Fl_Fontdesc* fl_fonts = built_in_table;
+
+Fl_XFont_On_Demand fl_xfont;
+void *fl_xftfont = 0;
+//static const char* fl_encoding_ = "iso8859-1";
+static const char* fl_encoding_ = "iso10646-1";
+
+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);
+ return;
+ }
+ Fl_Font_Descriptor* f = driver->font_descriptor();
+ if (fnum == driver->Fl_Graphics_Driver::font() && size == driver->size() && f && f->angle == angle)
+ return;
+ driver->Fl_Graphics_Driver::font(fnum, size);
+ Fl_Fontdesc *font = fl_fonts + fnum;
+ // search the fontsizes we have generated already
+ for (f = font->first; f; f = f->next) {
+ if (f->size == size && f->angle == angle)// && !strcasecmp(f->encoding, fl_encoding_))
+ break;
+ }
+ if (!f) {
+ f = new Fl_Font_Descriptor(font->name, size, angle);
+ f->next = font->first;
+ font->first = f;
+ }
+ driver->font_descriptor(f);
+#if XFT_MAJOR < 2
+ fl_xfont = f->font->u.core.font;
+#else
+ fl_xfont = NULL; // invalidate
+#endif // XFT_MAJOR < 2
+ fl_xftfont = (void*)f->font;
+}
+
+void Fl_Xlib_Graphics_Driver::font(Fl_Font fnum, Fl_Fontsize size) {
+ fl_xft_font(this,fnum,size,0);
+}
+
+static XftFont* fontopen(const char* name, Fl_Fontsize size, bool core, int angle) {
+ // Check: does it look like we have been passed an old-school XLFD fontname?
+ bool is_xlfd = false;
+ int hyphen_count = 0;
+ int comma_count = 0;
+ unsigned len = strlen(name);
+ if (len > 512) len = 512; // ensure we are not passed an unbounded font name
+ for(unsigned idx = 0; idx < len; idx++) {
+ if(name[idx] == '-') hyphen_count++; // check for XLFD hyphens
+ if(name[idx] == ',') comma_count++; // are there multiple names?
+ }
+ if(hyphen_count >= 14) is_xlfd = true; // Not a robust check, but good enough?
+
+ fl_open_display();
+
+ if(!is_xlfd) { // Not an XLFD - open as a XFT style name
+ XftFont *the_font = NULL; // the font we will return;
+ XftPattern *fnt_pat = XftPatternCreate(); // the pattern we will use for matching
+ int slant = XFT_SLANT_ROMAN;
+ int weight = XFT_WEIGHT_MEDIUM;
+
+ /* This "converts" FLTK-style font names back into "regular" names, extracting
+ * the BOLD and ITALIC codes as it does so - all FLTK font names are prefixed
+ * by 'I' (italic) 'B' (bold) 'P' (bold italic) or ' ' (regular) modifiers.
+ * This gives a fairly limited font selection ability, but is retained for
+ * compatibility reasons. If you really need a more complex choice, you are best
+ * calling Fl::set_fonts(*) then selecting the font by font-index rather than by
+ * name anyway. Probably.
+ * If you want to load a font who's name does actually begin with I, B or P, you
+ * MUST use a leading space OR simply use lowercase for the name...
+ */
+ /* This may be efficient, but it is non-obvious. */
+ switch (*name++) {
+ case 'I': slant = XFT_SLANT_ITALIC; break; // italic
+ case 'P': slant = XFT_SLANT_ITALIC; // bold-italic (falls-through)
+ case 'B': weight = XFT_WEIGHT_BOLD; break; // bold
+ case ' ': break; // regular
+ default: name--; // no prefix, restore name
+ }
+
+ if(comma_count) { // multiple comma-separated names were passed
+ char *local_name = strdup(name); // duplicate the full name so we can edit the copy
+ char *curr = local_name; // points to first name in string
+ char *nxt; // next name in string
+ do {
+ nxt = strchr(curr, ','); // find comma separator
+ if (nxt) {
+ *nxt = 0; // terminate first name
+ nxt++; // first char of next name
+ }
+
+ // Add the current name to the match pattern
+ XftPatternAddString(fnt_pat, XFT_FAMILY, curr);
+
+ if(nxt) curr = nxt; // move onto next name (if it exists)
+ // Now do a cut-down version of the FLTK name conversion.
+ // NOTE: we only use the slant and weight of the first name,
+ // subsequent names we ignore this for... But we still need to do the check.
+ switch (*curr++) {
+ case 'I': break; // italic
+ case 'P': // bold-italic (falls-through)
+ case 'B': break; // bold
+ case ' ': break; // regular
+ default: curr--; // no prefix, restore name
+ }
+
+ comma_count--; // decrement name sections count
+ } while (comma_count >= 0);
+ free(local_name); // release our local copy of font names
+ }
+ else { // single name was passed - add it directly
+ XftPatternAddString(fnt_pat, XFT_FAMILY, name);
+ }
+
+ // Construct a match pattern for the font we want...
+ XftPatternAddInteger(fnt_pat, XFT_WEIGHT, weight);
+ XftPatternAddInteger(fnt_pat, XFT_SLANT, slant);
+ XftPatternAddDouble (fnt_pat, XFT_PIXEL_SIZE, (double)size);
+ XftPatternAddString (fnt_pat, XFT_ENCODING, fl_encoding_);
+
+ // rotate font if angle!=0
+ if (angle !=0) {
+ XftMatrix m;
+ XftMatrixInit(&m);
+ XftMatrixRotate(&m,cos(M_PI*angle/180.),sin(M_PI*angle/180.));
+ XftPatternAddMatrix (fnt_pat, XFT_MATRIX,&m);
+ }
+
+ if (core) {
+ XftPatternAddBool(fnt_pat, XFT_CORE, FcTrue);
+ XftPatternAddBool(fnt_pat, XFT_RENDER, FcFalse);
+ }
+
+ XftPattern *match_pat; // the best available match on the system
+ XftResult match_result; // the result of our matching attempt
+
+ // query the system to find a match for this font
+ match_pat = XftFontMatch(fl_display, fl_screen, fnt_pat, &match_result);
+
+#if 0 // the XftResult never seems to get set to anything... abandon this code?
+ switch(match_result) { // how good a match is this font for our request?
+ case XftResultMatch:
+ puts("Object exists with the specified ID");
+ break;
+
+ case XftResultTypeMismatch:
+ puts("Object exists, but the type does not match");
+ break;
+
+ case XftResultNoId:
+ puts("Object exists, but has fewer values than specified");
+ break;
+
+ case FcResultOutOfMemory:
+ puts("FcResult: Malloc failed");
+ break;
+
+ case XftResultNoMatch:
+ puts("Object does not exist at all");
+ break;
+
+ default:
+ printf("Invalid XftResult status %d \n", match_result);
+ break;
+ }
+#endif
+
+#if 0 // diagnostic to print the "full name" of the font we matched. This works.
+ FcChar8 *picked_name = FcNameUnparse(match_pat);
+ printf("Match: %s\n", picked_name);
+ free(picked_name);
+#endif
+
+ // open the matched font
+ if (match_pat) the_font = XftFontOpenPattern(fl_display, match_pat);
+
+ if (!match_pat || !the_font) {
+ // last chance, just open any font in the right size
+ the_font = XftFontOpen (fl_display, fl_screen,
+ XFT_FAMILY, XftTypeString, "sans",
+ XFT_SIZE, XftTypeDouble, (double)size,
+ NULL);
+ XftPatternDestroy(fnt_pat);
+ if (!the_font) {
+ Fl::error("Unable to find fonts. Check your FontConfig configuration.\n");
+ exit(1);
+ }
+ return the_font;
+ }
+
+#if 0 // diagnostic to print the "full name" of the font we actually opened. This works.
+ FcChar8 *picked_name2 = FcNameUnparse(the_font->pattern);
+ printf("Open : %s\n", picked_name2);
+ free(picked_name2);
+#endif
+
+ XftPatternDestroy(fnt_pat);
+// XftPatternDestroy(match_pat); // FontConfig will destroy this resource for us. We must not!
+
+ return the_font;
+ }
+ else { // We were passed a font name in XLFD format
+ /* OksiD's X font code could handle being passed a comma separated list
+ * of XLFD's. It then attempted to find which font was "best" from this list.
+ * But XftFontOpenXlfd can not do this, so if a list is passed, we just
+ * terminate it at the first comma.
+ * A "better" solution might be to use XftXlfdParse() on each of the passed
+ * XLFD's to construct a "super-pattern" that incorporates attributes from all
+ * XLFD's and use that to perform a XftFontMatch(). Maybe...
+ */
+ char *local_name = strdup(name);
+ if(comma_count) { // This means we were passed multiple XLFD's
+ char *pc = strchr(local_name, ',');
+ *pc = 0; // terminate the XLFD at the first comma
+ }
+ XftFont *the_font = XftFontOpenXlfd(fl_display, fl_screen, local_name);
+ free(local_name);
+#if 0 // diagnostic to print the "full name" of the font we actually opened. This works.
+puts("Font Opened"); fflush(stdout);
+ FcChar8 *picked_name2 = FcNameUnparse(the_font->pattern);
+ printf("Open : %s\n", picked_name2); fflush(stdout);
+ free(picked_name2);
+#endif
+ return the_font;
+ }
+} // end of fontopen
+
+Fl_Font_Descriptor::Fl_Font_Descriptor(const char* name, Fl_Fontsize fsize, int fangle) {
+// encoding = fl_encoding_;
+ size = fsize;
+ angle = fangle;
+#if HAVE_GL
+ listbase = 0;
+#endif // HAVE_GL
+ font = fontopen(name, fsize, false, angle);
+}
+
+Fl_Font_Descriptor::~Fl_Font_Descriptor() {
+ if (this == fl_graphics_driver->font_descriptor()) fl_graphics_driver->font_descriptor(NULL);
+// XftFontClose(fl_display, font);
+}
+
+/* decodes the input UTF-8 string into a series of wchar_t characters.
+ n is set upon return to the number of characters.
+ Don't deallocate the returned memory.
+ */
+static const wchar_t *utf8reformat(const char *str, int& n)
+{
+ static const wchar_t empty[] = {0};
+ static wchar_t *buffer;
+ static int lbuf = 0;
+ int newn;
+ if (n == 0) return empty;
+ newn = fl_utf8towc(str, n, (wchar_t*)buffer, lbuf);
+ if (newn >= lbuf) {
+ lbuf = newn + 100;
+ if (buffer) free(buffer);
+ buffer = (wchar_t*)malloc(lbuf * sizeof(wchar_t));
+ n = fl_utf8towc(str, n, (wchar_t*)buffer, lbuf);
+ } else {
+ n = newn;
+ }
+ return buffer;
+}
+
+static void utf8extents(Fl_Font_Descriptor *desc, const char *str, int n, XGlyphInfo *extents)
+{
+ memset(extents, 0, sizeof(XGlyphInfo));
+ const wchar_t *buffer = utf8reformat(str, n);
+#ifdef __CYGWIN__
+ XftTextExtents16(fl_display, desc->font, (XftChar16 *)buffer, n, extents);
+#else
+ XftTextExtents32(fl_display, desc->font, (XftChar32 *)buffer, n, extents);
+#endif
+}
+
+int Fl_Xlib_Graphics_Driver::height() {
+ if (font_descriptor()) return font_descriptor()->font->ascent + font_descriptor()->font->descent;
+ else return -1;
+}
+
+int Fl_Xlib_Graphics_Driver::descent() {
+ if (font_descriptor()) return font_descriptor()->font->descent;
+ else return -1;
+}
+
+double Fl_Xlib_Graphics_Driver::width(const char* str, int n) {
+ if (!font_descriptor()) return -1.0;
+ XGlyphInfo i;
+ utf8extents(font_descriptor(), str, n, &i);
+ return i.xOff;
+}
+
+/*double fl_width(uchar c) {
+ return fl_graphics_driver->width((const char *)(&c), 1);
+}*/
+
+static double fl_xft_width(Fl_Font_Descriptor *desc, FcChar32 *str, int n) {
+ if (!desc) return -1.0;
+ XGlyphInfo i;
+ XftTextExtents32(fl_display, desc->font, str, n, &i);
+ return i.xOff;
+}
+
+double Fl_Xlib_Graphics_Driver::width(unsigned int c) {
+ return fl_xft_width(font_descriptor(), (FcChar32 *)(&c), 1);
+}
+
+void Fl_Xlib_Graphics_Driver::text_extents(const char *c, int n, int &dx, int &dy, int &w, int &h) {
+ if (!font_descriptor()) {
+ w = h = 0;
+ dx = dy = 0;
+ return;
+ }
+ XGlyphInfo gi;
+ utf8extents(font_descriptor(), c, n, &gi);
+
+ w = gi.width;
+ h = gi.height;
+ dx = -gi.x;
+ dy = -gi.y;
+} // fl_text_extents
+
+
+/* This code is used (mainly by opengl) to get a bitmapped font. The
+ * original XFT-1 code used XFT's "core" fonts methods to load an XFT
+ * font that was actually a X-bitmap font, that could then be readily
+ * used with GL. But XFT-2 does not provide that ability, and there
+ * is no easy method to use an XFT font directly with GL. So...
+*/
+
+# if XFT_MAJOR > 1
+// This function attempts, on XFT2 systems, to find a suitable "core" Xfont
+// for GL or other bitmap font needs (we dont have an XglUseXftFont(...) function.)
+// There's probably a better way to do this. I can't believe it is this hard...
+// Anyway... This code attempts to make an XLFD out of the fltk-style font
+// name it is passed, then tries to load that font. Surprisingly, this quite
+// often works - boxes that have XFT generally also have a fontserver that
+// can serve TTF and other fonts to X, and so the font name that fltk makes
+// from the XFT name often also "exists" as an "core" X font...
+// If this code fails to load the requested font, it falls back through a
+// series of tried 'n tested alternatives, ultimately resorting to what the
+// original fltk code did.
+// NOTE: On my test boxes (FC6, FC7, FC8, ubuntu8.04, 9.04, 9.10) this works
+// well for the fltk "built-in" font names.
+static XFontStruct* load_xfont_for_xft2(Fl_Graphics_Driver *driver) {
+ XFontStruct* xgl_font = 0;
+ int size = driver->size();
+ int fnum = driver->font();
+ const char *wt_med = "medium";
+ const char *wt_bold = "bold";
+ const char *weight = wt_med; // no specifc weight requested - accept any
+ char slant = 'r'; // regular non-italic by default
+ char xlfd[128]; // we will put our synthetic XLFD in here
+ char *pc = strdup(fl_fonts[fnum].name); // what font were we asked for?
+ const char *name = pc; // keep a handle to the original name for freeing later
+ // Parse the "fltk-name" of the font
+ switch (*name++) {
+ case 'I': slant = 'i'; break; // italic
+ case 'P': slant = 'i'; // bold-italic (falls-through)
+ case 'B': weight = wt_bold; break; // bold
+ case ' ': break; // regular
+ default: name--; // no prefix, restore name
+ }
+
+ // first, we do a query with no prefered size, to see if the font exists at all
+ snprintf(xlfd, 128, "-*-%s-%s-%c-*--*-*-*-*-*-*-*-*", name, weight, slant); // make up xlfd style name
+ xgl_font = XLoadQueryFont(fl_display, xlfd);
+ if(xgl_font) { // the face exists, but can we get it in a suitable size?
+ XFreeFont(fl_display, xgl_font); // release the non-sized version
+ snprintf(xlfd, 128, "-*-%s-%s-%c-*--*-%d-*-*-*-*-*-*", name, weight, slant, (size*10));
+ xgl_font = XLoadQueryFont(fl_display, xlfd); // attempt to load the font at the right size
+ }
+//puts(xlfd);
+
+ // try alternative names
+ if (!xgl_font) {
+ if (!strcmp(name, "sans")) {
+ name = "helvetica";
+ } else if (!strcmp(name, "mono")) {
+ name = "courier";
+ } else if (!strcmp(name, "serif")) {
+ name = "times";
+ } else if (!strcmp(name, "screen")) {
+ name = "lucidatypewriter";
+ } else if (!strcmp(name, "dingbats")) {
+ name = "zapf dingbats";
+ }
+ snprintf(xlfd, 128, "-*-*%s*-%s-%c-*--*-%d-*-*-*-*-*-*", name, weight, slant, (size*10));
+ xgl_font = XLoadQueryFont(fl_display, xlfd);
+ }
+ free(pc); // release our copy of the font name
+
+ // if we have nothing loaded, try a generic proportional font
+ if(!xgl_font) {
+ snprintf(xlfd, 128, "-*-helvetica-*-%c-*--*-%d-*-*-*-*-*-*", slant, (size*10));
+ xgl_font = XLoadQueryFont(fl_display, xlfd);
+ }
+ // If that still didn't work, try this instead
+ if(!xgl_font) {
+ snprintf(xlfd, 128, "-*-courier-medium-%c-*--*-%d-*-*-*-*-*-*", slant, (size*10));
+ xgl_font = XLoadQueryFont(fl_display, xlfd);
+ }
+//printf("glf: %d\n%s\n%s\n", size, xlfd, fl_fonts[fl_font_].name);
+//if(xgl_font) puts("ok");
+
+ // Last chance fallback - this usually loads something...
+ if (!xgl_font) xgl_font = XLoadQueryFont(fl_display, "fixed");
+
+ return xgl_font;
+} // end of load_xfont_for_xft2
+# endif
+
+static XFontStruct* fl_xxfont(Fl_Graphics_Driver *driver) {
+# if XFT_MAJOR > 1
+ // kludge! XFT 2 and later does not provide core fonts for us to use with GL
+ // try to load a bitmap X font instead
+ static XFontStruct* xgl_font = 0;
+ static int glsize = 0;
+ static int glfont = -1;
+ // Do we need to load a new font?
+ if ((!xgl_font) || (glsize != driver->size()) || (glfont != driver->font())) {
+ // create a dummy XLFD for some font of the appropriate size...
+ if (xgl_font) XFreeFont(fl_display, xgl_font); // font already loaded, free it - this *might* be a Bad Idea
+ glsize = driver->size(); // record current font size
+ glfont = driver->font(); // and face
+ xgl_font = load_xfont_for_xft2(driver);
+ }
+ return xgl_font;
+# else // XFT-1 provides a means to load a "core" font directly
+ if (driver->font_descriptor()->font->core) {
+ return driver->font_descriptor()->font->u.core.font; // is the current font a "core" font? If so, use it.
+ }
+ static XftFont* xftfont;
+ if (xftfont) XftFontClose (fl_display, xftfont);
+ xftfont = fontopen(fl_fonts[driver->font()].name, driver->size(), true, 0); // else request XFT to load a suitable "core" font instead.
+ return xftfont->u.core.font;
+# endif // XFT_MAJOR > 1
+}
+
+XFontStruct* Fl_XFont_On_Demand::value() {
+ if (!ptr) ptr = fl_xxfont(fl_graphics_driver);
+ return ptr;
+}
+
+#if USE_OVERLAY
+// Currently Xft does not work with colormapped visuals, so this probably
+// does not work unless you have a true-color overlay.
+extern bool fl_overlay;
+extern Colormap fl_overlay_colormap;
+extern XVisualInfo* fl_overlay_visual;
+#endif
+
+// For some reason Xft produces errors if you destroy a window whose id
+// still exists in an XftDraw structure. It would be nice if this is not
+// true, a lot of junk is needed to try to stop this:
+
+static XftDraw* draw_;
+static Window draw_window;
+#if USE_OVERLAY
+static XftDraw* draw_overlay;
+static Window draw_overlay_window;
+#endif
+
+void fl_destroy_xft_draw(Window id) {
+ if (id == draw_window)
+ XftDrawChange(draw_, draw_window = fl_message_window);
+#if USE_OVERLAY
+ if (id == draw_overlay_window)
+ XftDrawChange(draw_overlay, draw_overlay_window = fl_message_window);
+#endif
+}
+
+void Fl_Xlib_Graphics_Driver::draw(const char *str, int n, int x, int y) {
+ if ( !this->font_descriptor() ) {
+ this->font(FL_HELVETICA, FL_NORMAL_SIZE);
+ }
+#if USE_OVERLAY
+ XftDraw*& draw_ = fl_overlay ? draw_overlay : ::draw_;
+ if (fl_overlay) {
+ if (!draw_)
+ draw_ = XftDrawCreate(fl_display, draw_overlay_window = fl_window,
+ fl_overlay_visual->visual, fl_overlay_colormap);
+ else //if (draw_overlay_window != fl_window)
+ XftDrawChange(draw_, draw_overlay_window = fl_window);
+ } else
+#endif
+ if (!draw_)
+ draw_ = XftDrawCreate(fl_display, draw_window = fl_window,
+ fl_visual->visual, fl_colormap);
+ else //if (draw_window != fl_window)
+ XftDrawChange(draw_, draw_window = fl_window);
+
+ Region region = fl_clip_region();
+ if (region && XEmptyRegion(region)) return;
+ XftDrawSetClip(draw_, region);
+
+ // Use fltk's color allocator, copy the results to match what
+ // XftCollorAllocValue returns:
+ XftColor color;
+ color.pixel = fl_xpixel(Fl_Graphics_Driver::color());
+ uchar r,g,b; Fl::get_color(Fl_Graphics_Driver::color(), r,g,b);
+ color.color.red = ((int)r)*0x101;
+ color.color.green = ((int)g)*0x101;
+ color.color.blue = ((int)b)*0x101;
+ color.color.alpha = 0xffff;
+
+ const wchar_t *buffer = utf8reformat(str, n);
+#ifdef __CYGWIN__
+ XftDrawString16(draw_, &color, font_descriptor()->font, x, y, (XftChar16 *)buffer, n);
+#else
+ XftDrawString32(draw_, &color, font_descriptor()->font, x, y, (XftChar32 *)buffer, n);
+#endif
+}
+
+void Fl_Xlib_Graphics_Driver::draw(int angle, const char *str, int n, int x, int y) {
+ fl_xft_font(this, this->Fl_Graphics_Driver::font(), this->size(), angle);
+ this->draw(str, n, (int)x, (int)y);
+ fl_xft_font(this, this->Fl_Graphics_Driver::font(), this->size(), 0);
+}
+
+static void fl_drawUCS4(Fl_Graphics_Driver *driver, const FcChar32 *str, int n, int x, int y) {
+#if USE_OVERLAY
+ XftDraw*& draw_ = fl_overlay ? draw_overlay : ::draw_;
+ if (fl_overlay) {
+ if (!draw_)
+ draw_ = XftDrawCreate(fl_display, draw_overlay_window = fl_window,
+ fl_overlay_visual->visual, fl_overlay_colormap);
+ else //if (draw_overlay_window != fl_window)
+ XftDrawChange(draw_, draw_overlay_window = fl_window);
+ } else
+#endif
+ if (!draw_)
+ draw_ = XftDrawCreate(fl_display, draw_window = fl_window,
+ fl_visual->visual, fl_colormap);
+ else //if (draw_window != fl_window)
+ XftDrawChange(draw_, draw_window = fl_window);
+
+ Region region = fl_clip_region();
+ if (region && XEmptyRegion(region)) return;
+ XftDrawSetClip(draw_, region);
+
+ // Use fltk's color allocator, copy the results to match what
+ // XftCollorAllocValue returns:
+ XftColor color;
+ color.pixel = fl_xpixel(driver->color());
+ uchar r,g,b; Fl::get_color(driver->color(), r,g,b);
+ color.color.red = ((int)r)*0x101;
+ color.color.green = ((int)g)*0x101;
+ color.color.blue = ((int)b)*0x101;
+ color.color.alpha = 0xffff;
+
+ XftDrawString32(draw_, &color, driver->font_descriptor()->font, x, y, (FcChar32 *)str, n);
+}
+
+
+void Fl_Xlib_Graphics_Driver::rtl_draw(const char* c, int n, int x, int y) {
+
+#if defined(__GNUC__)
+// FIXME: warning Need to improve this XFT right to left draw function
+#endif /*__GNUC__*/
+
+// This actually draws LtoR, but aligned to R edge with the glyph order reversed...
+// but you can't just byte-rev a UTF-8 string, that isn't valid.
+// You can reverse a UCS4 string though...
+ int num_chars, wid, utf_len = strlen(c);
+ FcChar8 *u8 = (FcChar8 *)c;
+ FcBool valid = FcUtf8Len(u8, utf_len, &num_chars, &wid);
+ if (!valid)
+ {
+ // badly formed Utf-8 input string
+ return;
+ }
+ if (num_chars < n) n = num_chars; // limit drawing to usable characters in input array
+ FcChar32 *ucs_txt = new FcChar32[n+1];
+ FcChar32* pu;
+ int out, sz;
+ ucs_txt[n] = 0;
+ out = n-1;
+ while ((out >= 0) && (utf_len > 0))
+ {
+ pu = &ucs_txt[out];
+ sz = FcUtf8ToUcs4(u8, pu, utf_len);
+ utf_len = utf_len - sz;
+ u8 = u8 + sz;
+ out = out - 1;
+ }
+ // Now we have a UCS4 version of the input text, reversed, in ucs_txt
+ int offs = (int)fl_xft_width(font_descriptor(), ucs_txt, n);
+ fl_drawUCS4(this, ucs_txt, n, (x-offs), y);
+
+ delete[] ucs_txt;
+}
+#endif
+
+//
+// End of "$Id$"
+//
diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_line_style.cxx b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_line_style.cxx
new file mode 100644
index 000000000..a20ace778
--- /dev/null
+++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_line_style.cxx
@@ -0,0 +1,71 @@
+//
+// "$Id$"
+//
+// Line style code for the Fast Light Tool Kit (FLTK).
+//
+// Copyright 1998-2016 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:
+//
+// http://www.fltk.org/COPYING.php
+//
+// Please report all bugs and problems on the following page:
+//
+// http://www.fltk.org/str.php
+//
+
+#ifndef FL_CFG_GFX_XLIB_LINE_STYLE_CXX
+#define FL_CFG_GFX_XLIB_LINE_STYLE_CXX
+
+/**
+ \file xlib_line_style.cxx
+ \brief Line style drawing utility hiding different platforms.
+*/
+
+#include "Fl_Xlib_Graphics_Driver.h"
+
+void Fl_Xlib_Graphics_Driver::line_style(int style, int width, char* dashes) {
+
+ // save line width in global variable for X11 clipping
+ if (width == 0) fl_line_width_ = 1;
+ else fl_line_width_ = width>0 ? width : -width;
+
+ int ndashes = dashes ? strlen(dashes) : 0;
+ // emulate the WIN32 dash patterns on X
+ char buf[7];
+ if (!ndashes && (style&0xff)) {
+ int w = width ? width : 1;
+ char dash, dot, gap;
+ // adjust lengths to account for cap:
+ if (style & 0x200) {
+ dash = char(2*w);
+ dot = 1; // unfortunately 0 does not work
+ gap = char(2*w-1);
+ } else {
+ dash = char(3*w);
+ dot = gap = char(w);
+ }
+ char* p = dashes = buf;
+ switch (style & 0xff) {
+ case FL_DASH: *p++ = dash; *p++ = gap; break;
+ case FL_DOT: *p++ = dot; *p++ = gap; break;
+ case FL_DASHDOT: *p++ = dash; *p++ = gap; *p++ = dot; *p++ = gap; break;
+ case FL_DASHDOTDOT: *p++ = dash; *p++ = gap; *p++ = dot; *p++ = gap; *p++ = dot; *p++ = gap; break;
+ }
+ ndashes = p-buf;
+ }
+ static int Cap[4] = {CapButt, CapButt, CapRound, CapProjecting};
+ static int Join[4] = {JoinMiter, JoinMiter, JoinRound, JoinBevel};
+ XSetLineAttributes(fl_display, fl_gc, width,
+ ndashes ? LineOnOffDash : LineSolid,
+ Cap[(style>>8)&3], Join[(style>>12)&3]);
+ if (ndashes) XSetDashes(fl_display, fl_gc, 0, dashes, ndashes);
+}
+
+#endif // FL_CFG_GFX_XLIB_LINE_STYLE_CXX
+
+//
+// End of "$Id$".
+//
diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_rect.cxx b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_rect.cxx
new file mode 100644
index 000000000..225b578d1
--- /dev/null
+++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_rect.cxx
@@ -0,0 +1,339 @@
+//
+// "$Id$"
+//
+// Rectangle drawing routines for the Fast Light Tool Kit (FLTK).
+//
+// Copyright 1998-2012 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:
+//
+// http://www.fltk.org/COPYING.php
+//
+// Please report all bugs and problems on the following page:
+//
+// http://www.fltk.org/str.php
+//
+
+
+#ifndef FL_CFG_GFX_XLIB_RECT_CXX
+#define FL_CFG_GFX_XLIB_RECT_CXX
+
+
+/**
+ \file xlib_rect.cxx
+ \brief X11 Xlib specific line and polygon drawing with integer coordinates.
+ */
+
+
+#include "Fl_Xlib_Graphics_Driver.h"
+
+
+#ifndef SHRT_MAX
+#define SHRT_MAX (32767)
+#endif
+
+/*
+ We need to check some coordinates for areas for clipping before we
+ use X functions, because X can't handle coordinates outside the 16-bit
+ range. Since all windows use relative coordinates > 0, we do also
+ check for negative values. X11 only, see also STR #2304.
+
+ Note that this is only necessary for large objects, where only a
+ part of the object is visible. The draw() functions (e.g. box
+ drawing) must be clipped correctly. This is usually only a matter
+ for large container widgets. The individual child widgets will be
+ clipped completely.
+
+ We define the usable X coordinate space as [ -LW : SHRT_MAX - LW ]
+ where LW = current line width for drawing. This is done so that
+ horizontal and vertical line drawing works correctly, even in real
+ border cases, e.g. drawing a rectangle slightly outside the top left
+ window corner, but with a line width so that a part of the line should
+ be visible (in this case 2 of 5 pixels):
+
+ fl_line_style (FL_SOLID,5); // line width = 5
+ fl_rect (-1,-1,100,100); // top/left: 2 pixels visible
+
+ In this example case, no clipping would be done, because X can
+ handle it and clip unneeded pixels.
+
+ Note that we must also take care of the case where fl_line_width_
+ is zero (maybe unitialized). If this is the case, we assume a line
+ width of 1.
+
+ Todo: Arbitrary line drawings (e.g. polygons) and clip regions
+ are not yet done.
+
+ Note:
+
+ We could use max. screen coordinates instead of SHRT_MAX, but that
+ would need more work and would probably be slower. We assume that
+ all window coordinates are >= 0 and that no window extends up to
+ 32767 - LW (where LW = current line width). Thus it is safe to clip
+ all coordinates to this range before calling X functions. If this
+ is not true, then clip_to_short() and clip_x() must be redefined.
+
+ It would be somewhat easier if we had fl_clip_w and fl_clip_h, as
+ defined in FLTK 2.0 (for the upper clipping bounds)...
+ */
+
+/*
+ clip_to_short() returns 1, if the area is invisible (clipped),
+ because ...
+
+ (a) w or h are <= 0 i.e. nothing is visible
+ (b) x+w or y+h are < kmin i.e. left of or above visible area
+ (c) x or y are > kmax i.e. right of or below visible area
+
+ kmin and kmax are the minimal and maximal X coordinate values,
+ as defined above. In this case x, y, w, and h are not changed.
+
+ It returns 0, if the area is potentially visible and X can handle
+ clipping. x, y, w, and h may have been adjusted to fit into the
+ X coordinate space.
+
+ Use this for clipping rectangles, as used in fl_rect() and
+ fl_rectf().
+ */
+static int clip_to_short(int &x, int &y, int &w, int &h) {
+
+ int lw = (fl_line_width_ > 0) ? fl_line_width_ : 1;
+ int kmin = -lw;
+ int kmax = SHRT_MAX - lw;
+
+ if (w <= 0 || h <= 0) return 1; // (a)
+ if (x+w < kmin || y+h < kmin) return 1; // (b)
+ if (x > kmax || y > kmax) return 1; // (c)
+
+ if (x < kmin) { w -= (kmin-x); x = kmin; }
+ if (y < kmin) { h -= (kmin-y); y = kmin; }
+ if (x+w > kmax) w = kmax - x;
+ if (y+h > kmax) h = kmax - y;
+
+ return 0;
+}
+
+/*
+ clip_x() returns a coordinate value clipped to the 16-bit coordinate
+ space (see above). This can be used to draw horizontal and vertical
+ lines that can be handled by X11. Each single coordinate value can
+ be clipped individually, and the result can be used directly, e.g.
+ in fl_xyline() and fl_yxline(). Note that this can't be used for
+ arbitrary lines (not horizontal or vertical).
+ */
+static int clip_x (int x) {
+
+ int lw = (fl_line_width_ > 0) ? fl_line_width_ : 1;
+ int kmin = -lw;
+ int kmax = SHRT_MAX - lw;
+
+ if (x < kmin)
+ x = kmin;
+ else if (x > kmax)
+ x = kmax;
+ return x;
+}
+
+// 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;
+}
+
+// --- line and polygon drawing with integer coordinates
+
+void Fl_Xlib_Graphics_Driver::point(int x, int y) {
+ XDrawPoint(fl_display, fl_window, fl_gc, clip_x(x), clip_x(y));
+}
+
+void Fl_Xlib_Graphics_Driver::rect(int x, int y, int w, int h) {
+ if (w<=0 || h<=0) return;
+ if (!clip_to_short(x, y, w, h))
+ XDrawRectangle(fl_display, fl_window, fl_gc, x, y, w-1, h-1);
+}
+
+void Fl_Xlib_Graphics_Driver::rectf(int x, int y, int w, int h) {
+ if (w<=0 || h<=0) return;
+ if (!clip_to_short(x, y, w, h))
+ XFillRectangle(fl_display, fl_window, fl_gc, x, y, w, h);
+}
+
+void Fl_Xlib_Graphics_Driver::line(int x, int y, int x1, int y1) {
+ XDrawLine(fl_display, fl_window, fl_gc, x, y, x1, y1);
+}
+
+void Fl_Xlib_Graphics_Driver::line(int x, int y, int x1, int y1, int x2, int y2) {
+ XPoint p[3];
+ p[0].x = x; p[0].y = y;
+ p[1].x = x1; p[1].y = y1;
+ p[2].x = x2; p[2].y = y2;
+ XDrawLines(fl_display, fl_window, fl_gc, p, 3, 0);
+}
+
+void Fl_Xlib_Graphics_Driver::xyline(int x, int y, int x1) {
+ XDrawLine(fl_display, fl_window, fl_gc, clip_x(x), clip_x(y), clip_x(x1), clip_x(y));
+}
+
+void Fl_Xlib_Graphics_Driver::xyline(int x, int y, int x1, int y2) {
+ XPoint p[3];
+ p[0].x = clip_x(x); p[0].y = p[1].y = clip_x(y);
+ p[1].x = p[2].x = clip_x(x1); p[2].y = clip_x(y2);
+ XDrawLines(fl_display, fl_window, fl_gc, p, 3, 0);
+}
+
+void Fl_Xlib_Graphics_Driver::xyline(int x, int y, int x1, int y2, int x3) {
+ XPoint p[4];
+ p[0].x = clip_x(x); p[0].y = p[1].y = clip_x(y);
+ p[1].x = p[2].x = clip_x(x1); p[2].y = p[3].y = clip_x(y2);
+ p[3].x = clip_x(x3);
+ XDrawLines(fl_display, fl_window, fl_gc, p, 4, 0);
+}
+
+void Fl_Xlib_Graphics_Driver::yxline(int x, int y, int y1) {
+ XDrawLine(fl_display, fl_window, fl_gc, clip_x(x), clip_x(y), clip_x(x), clip_x(y1));
+}
+
+void Fl_Xlib_Graphics_Driver::yxline(int x, int y, int y1, int x2) {
+ XPoint p[3];
+ p[0].x = p[1].x = clip_x(x); p[0].y = clip_x(y);
+ p[1].y = p[2].y = clip_x(y1); p[2].x = clip_x(x2);
+ XDrawLines(fl_display, fl_window, fl_gc, p, 3, 0);
+}
+
+void Fl_Xlib_Graphics_Driver::yxline(int x, int y, int y1, int x2, int y3) {
+ XPoint p[4];
+ p[0].x = p[1].x = clip_x(x); p[0].y = clip_x(y);
+ p[1].y = p[2].y = clip_x(y1); p[2].x = p[3].x = clip_x(x2);
+ p[3].y = clip_x(y3);
+ XDrawLines(fl_display, fl_window, fl_gc, p, 4, 0);
+}
+
+void Fl_Xlib_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2) {
+ XPoint p[4];
+ p[0].x = x; p[0].y = y;
+ p[1].x = x1; p[1].y = y1;
+ p[2].x = x2; p[2].y = y2;
+ p[3].x = x; p[3].y = y;
+ XDrawLines(fl_display, fl_window, fl_gc, p, 4, 0);
+}
+
+void Fl_Xlib_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) {
+ XPoint p[5];
+ p[0].x = x; p[0].y = y;
+ p[1].x = x1; p[1].y = y1;
+ p[2].x = x2; p[2].y = y2;
+ p[3].x = x3; p[3].y = y3;
+ p[4].x = x; p[4].y = y;
+ XDrawLines(fl_display, fl_window, fl_gc, p, 5, 0);
+}
+
+void Fl_Xlib_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2) {
+ XPoint p[4];
+ p[0].x = x; p[0].y = y;
+ p[1].x = x1; p[1].y = y1;
+ p[2].x = x2; p[2].y = y2;
+ p[3].x = x; p[3].y = y;
+ XFillPolygon(fl_display, fl_window, fl_gc, p, 3, Convex, 0);
+ XDrawLines(fl_display, fl_window, fl_gc, p, 4, 0);
+}
+
+void Fl_Xlib_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) {
+ XPoint p[5];
+ p[0].x = x; p[0].y = y;
+ p[1].x = x1; p[1].y = y1;
+ p[2].x = x2; p[2].y = y2;
+ p[3].x = x3; p[3].y = y3;
+ p[4].x = x; p[4].y = y;
+ XFillPolygon(fl_display, fl_window, fl_gc, p, 4, Convex, 0);
+ XDrawLines(fl_display, fl_window, fl_gc, p, 5, 0);
+}
+
+// --- clipping
+
+void Fl_Xlib_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);
+ Fl_Region current = rstack[rstackptr];
+ if (current) {
+ Fl_Region temp = XCreateRegion();
+ XIntersectRegion(current, r, temp);
+ XDestroyRegion(r);
+ r = temp;
+ }
+ } else { // make empty clip region:
+ r = XCreateRegion();
+ }
+ if (rstackptr < region_stack_max) rstack[++rstackptr] = r;
+ else Fl::warning("Fl_Xlib_Graphics_Driver::push_clip: clip stack overflow!\n");
+ fl_restore_clip();
+}
+
+int Fl_Xlib_Graphics_Driver::clip_box(int x, int y, int w, int h, int& X, int& Y, int& W, int& H){
+ X = x; Y = y; W = w; H = h;
+ Fl_Region r = rstack[rstackptr];
+ if (!r) return 0;
+ switch (XRectInRegion(r, x, y, w, h)) {
+ case 0: // completely outside
+ W = H = 0;
+ return 2;
+ case 1: // completely inside:
+ return 0;
+ default: // partial:
+ break;
+ }
+ 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);
+ return 1;
+}
+
+int Fl_Xlib_Graphics_Driver::not_clipped(int x, int y, int w, int h) {
+ if (x+w <= 0 || y+h <= 0) return 0;
+ Fl_Region r = rstack[rstackptr];
+ if (!r) return 1;
+ // 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);
+}
+
+// make there be no clip (used by fl_begin_offscreen() only!)
+void Fl_Xlib_Graphics_Driver::push_no_clip() {
+ if (rstackptr < region_stack_max) rstack[++rstackptr] = 0;
+ else Fl::warning("fl_push_no_cFl_Xlib_Graphics_Driver::push_no_cliplip: clip stack overflow!\n");
+ fl_restore_clip();
+}
+
+// pop back to previous clip:
+void Fl_Xlib_Graphics_Driver::pop_clip() {
+ if (rstackptr > 0) {
+ Fl_Region oldr = rstack[rstackptr--];
+ if (oldr) XDestroyRegion(oldr);
+ } else Fl::warning("Fl_Xlib_Graphics_Driver::pop_clip: clip stack underflow!\n");
+ fl_restore_clip();
+}
+
+void Fl_Xlib_Graphics_Driver::restore_clip() {
+ fl_clip_state_number++;
+ Fl_Region r = rstack[rstackptr];
+ if (r) XSetRegion(fl_display, fl_gc, r);
+ else XSetClipMask(fl_display, fl_gc, 0);
+}
+
+#endif // FL_CFG_GFX_XLIB_RECT_CXX
+
+//
+// End of "$Id$".
+//
diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_vertex.cxx b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_vertex.cxx
new file mode 100644
index 000000000..4c559ad8c
--- /dev/null
+++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_vertex.cxx
@@ -0,0 +1,116 @@
+//
+// "$Id$"
+//
+// Portable drawing routines for the Fast Light Tool Kit (FLTK).
+//
+// Copyright 1998-2016 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:
+//
+// http://www.fltk.org/COPYING.php
+//
+// Please report all bugs and problems on the following page:
+//
+// http://www.fltk.org/str.php
+//
+
+#ifndef FL_CFG_GFX_XLIB_VERTEX_CXX
+#define FL_CFG_GFX_XLIB_VERTEX_CXX
+
+/**
+ \file xlib_vertex.cxx
+ \brief Portable drawing code for drawing arbitrary shapes with
+ simple 2D transformations, implemented for X11 Xlib.
+ */
+
+#include "Fl_Xlib_Graphics_Driver.h"
+
+#include <FL/fl_draw.H>
+#include <FL/x.H>
+#include <FL/math.h>
+
+
+void Fl_Xlib_Graphics_Driver::transformed_vertex(double xf, double yf) {
+ transformed_vertex0(COORD_T(rint(xf)), COORD_T(rint(yf)));
+}
+
+void Fl_Xlib_Graphics_Driver::vertex(double x,double y) {
+ transformed_vertex0(COORD_T(x*m.a + y*m.c + m.x), COORD_T(x*m.b + y*m.d + m.y));
+}
+
+void Fl_Xlib_Graphics_Driver::end_points() {
+ if (n>1) XDrawPoints(fl_display, fl_window, fl_gc, p, n, 0);
+}
+
+void Fl_Xlib_Graphics_Driver::end_line() {
+ if (n < 2) {
+ end_points();
+ return;
+ }
+ if (n>1) XDrawLines(fl_display, fl_window, fl_gc, p, n, 0);
+}
+
+void Fl_Xlib_Graphics_Driver::end_loop() {
+ fixloop();
+ if (n>2) transformed_vertex((COORD_T)p[0].x, (COORD_T)p[0].y);
+ end_line();
+}
+
+void Fl_Xlib_Graphics_Driver::end_polygon() {
+ fixloop();
+ if (n < 3) {
+ end_line();
+ return;
+ }
+ if (n>2) XFillPolygon(fl_display, fl_window, fl_gc, p, n, Convex, 0);
+}
+
+void Fl_Xlib_Graphics_Driver::begin_complex_polygon() {
+ begin_polygon();
+ gap_ = 0;
+}
+
+void Fl_Xlib_Graphics_Driver::gap() {
+ while (n>gap_+2 && p[n-1].x == p[gap_].x && p[n-1].y == p[gap_].y) n--;
+ if (n > gap_+2) {
+ transformed_vertex((COORD_T)p[gap_].x, (COORD_T)p[gap_].y);
+ gap_ = n;
+ } else {
+ n = gap_;
+ }
+}
+
+void Fl_Xlib_Graphics_Driver::end_complex_polygon() {
+ gap();
+ if (n < 3) {
+ end_line();
+ return;
+ }
+ if (n>2) XFillPolygon(fl_display, fl_window, fl_gc, p, n, 0, 0);
+}
+
+// shortcut the closed circles so they use XDrawArc:
+// warning: these do not draw rotated ellipses correctly!
+// See fl_arc.c for portable version.
+
+void Fl_Xlib_Graphics_Driver::circle(double x, double y,double r) {
+ double xt = transform_x(x,y);
+ double yt = transform_y(x,y);
+ double rx = r * (m.c ? sqrt(m.a*m.a+m.c*m.c) : fabs(m.a));
+ double ry = r * (m.b ? sqrt(m.b*m.b+m.d*m.d) : fabs(m.d));
+ int llx = (int)rint(xt-rx);
+ int w = (int)rint(xt+rx)-llx;
+ int lly = (int)rint(yt-ry);
+ int h = (int)rint(yt+ry)-lly;
+
+ (what == POLYGON ? XFillArc : XDrawArc)
+ (fl_display, fl_window, fl_gc, llx, lly, w, h, 0, 360*64);
+}
+
+#endif // FL_CFG_GFX_XLIB_VERTEX_CXX
+
+//
+// End of "$Id$".
+//