Introduce HiDPI + rescaling support for the X11 platform (+ partial support for WIN32)

Corresponds to STR #3320
1) HiDPI support consists in detecting the adequate scaling factor for the screen on which
FLTK maps a window, and scaling all FLTK units by this factor. FLTK tries to detect the correct
value of this factor at startup (see more details below). Environment variable
FLTK_SCALING_FACTOR can also be used to set this value.
2) Rescaling support consists in changing the scaling factor of all FLTK windows
in reply to ctrl/+/-/0/ keystrokes.

More details for the various platforms :

- X11: Support is very advanced. Some details need still to be improved.
Automatic detection of the correct starting value of the scaling factor works well
with the gnome desktop. The present code contains no support for this on
other desktops.  FLTK_SCALING_FACTOR provides a workaround.

-WIN32: Support is incomplete at this point, although many test
applications have partial or complete HiDPI and scaling support.
The current value of the system's scaling factor is correctly detected
at application startup. Apps respond to changes of this value in real time.
Support needs to define the FLTK_HIDPI_SUPPORT preprocessor variable
at compile time. This way, standard builds produce a code with the
default WIN32 HiDPI support, that is, where all graphics goes to an internal
buffer that gets enlarged by the system and then mapped to the HiDPI
display. To experiment with (or develop) the new HiDPI support requires
a modified build procedure in which  FLTK_HIDPI_SUPPORT is defined
at compile time. When the support will be complete, the requirement for the
definition of this preprocessor variable will be removed. The present commit
contains support for a single scaling factor. Eventually, per-screen scaling
factors should be implemented, as done for X11.

- MacOS: this commit does not give new HiDPI for this platform.
Eventually, window rescaling in reply to command/+/-/0/ is desirable.
Per-screen scaling factor makes no sense on this platform because
the OS itself takes care of the difference between the resolutions of
traditional and retina displays.


git-svn-id: file:///fltk/svn/fltk/branches/branch-1.4@12239 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
Manolo Gouy 2017-05-17 11:54:18 +00:00
parent 22a5dd4fcf
commit f48750b0f4
51 changed files with 2097 additions and 605 deletions

View File

@ -3,7 +3,7 @@
//
// Bitmap header file for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2010 by Bill Spitzak and others.
// Copyright 1998-2017 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
@ -45,15 +45,16 @@ private:
int &X, int &Y, int &W, int &H);
/** for internal use */
fl_uintptr_t id_;
float cache_scale_; // graphics scaling value when id_ was computed
public:
/** The constructors create a new bitmap from the specified bitmap data */
Fl_Bitmap(const uchar *bits, int W, int H) :
Fl_Image(W,H,0), array(bits), alloc_array(0), id_(0) {data((const char **)&array, 1);}
Fl_Image(W,H,0), array(bits), alloc_array(0), id_(0), cache_scale_(1) {data((const char **)&array, 1);}
/** The constructors create a new bitmap from the specified bitmap data */
Fl_Bitmap(const char *bits, int W, int H) :
Fl_Image(W,H,0), array((const uchar *)bits), alloc_array(0), id_(0) {data((const char **)&array, 1);}
Fl_Image(W,H,0), array((const uchar *)bits), alloc_array(0), id_(0), cache_scale_(1) {data((const char **)&array, 1);}
virtual ~Fl_Bitmap();
virtual Fl_Image *copy(int W, int H);
Fl_Image *copy() { return copy(w(), h()); }

View File

@ -4,7 +4,7 @@
// Definition of classes Fl_Graphics_Driver, Fl_Surface_Device, Fl_Display_Device
// for the Fast Light Tool Kit (FLTK).
//
// Copyright 2016 by Bill Spitzak and others.
// Copyright 2016-2017 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
@ -127,6 +127,7 @@ class Fl_Cocoa_Gl_Window_Driver : public Fl_Gl_Window_Driver {
class Fl_WinAPI_Gl_Window_Driver : public Fl_Gl_Window_Driver {
friend class Fl_Gl_Window_Driver;
Fl_WinAPI_Gl_Window_Driver(Fl_Gl_Window *win) : Fl_Gl_Window_Driver(win) {}
virtual float pixels_per_unit();
virtual int mode_(int m, const int *a);
virtual void make_current_after();
virtual void swap_buffers();
@ -156,6 +157,7 @@ class Fl_WinAPI_Gl_Window_Driver : public Fl_Gl_Window_Driver {
class Fl_X11_Gl_Window_Driver : public Fl_Gl_Window_Driver {
friend class Fl_Gl_Window_Driver;
Fl_X11_Gl_Window_Driver(Fl_Gl_Window *win) : Fl_Gl_Window_Driver(win) {}
virtual float pixels_per_unit();
virtual void before_show(int& need_redraw);
virtual int mode_(int m, const int *a);
virtual void swap_buffers();

View File

@ -18,7 +18,7 @@
//
/** \file Fl_Graphics_Driver.H
\brief declaration of classe Fl_Graphics_Driver.
\brief declaration of class Fl_Graphics_Driver.
*/
#ifndef FL_GRAPHICS_DRIVER_H
@ -33,12 +33,7 @@
class Fl_Graphics_Driver;
class Fl_Shared_Image;
/** a platform-specific class implementing a system font */
class Fl_Font_Descriptor
#ifdef FL_DOXYGEN
{}
#endif
;
class Fl_Font_Descriptor;
/** \brief Points to the driver that currently receives all graphics requests */
FL_EXPORT extern Fl_Graphics_Driver *fl_graphics_driver;
@ -57,19 +52,28 @@ struct Fl_Fontdesc;
#define FL_REGION_STACK_SIZE 10
#define FL_MATRIX_STACK_SIZE 32
/**
\brief A virtual class subclassed for each graphics driver FLTK uses.
An abstract class subclassed for each graphics driver FLTK uses.
Typically, FLTK applications do not use directly objects from this class. Rather, they perform
drawing operations (e.g., fl_rectf()) that operate on the current drawing surface (see Fl_Surface_Device).
Drawing operations are functionally presented in \ref drawing and as function lists
in the \ref fl_drawings and \ref fl_attributes modules. The \ref fl_graphics_driver global variable
gives at any time the graphics driver used by all drawing operations. Its value changes when
drawing operations are directed to another drawing surface by Fl_Surface_Device::set_current().
in the \ref fl_drawings and \ref fl_attributes modules.
\p <tt>Fl_Surface_Device::surface()->driver()</tt>
gives at any time the graphics driver used by all drawing operations.
For compatibility with older FLTK versions, the \ref fl_graphics_driver global variable gives the same result.
Its value changes when
drawing operations are directed to another drawing surface by Fl_Surface_Device::push_current() /
Fl_Surface_Device::pop_current() / Fl_Surface_Device::set_current().
\p The Fl_Graphics_Driver class is of interest if one wants to perform new kinds of drawing operations.
An example would be to draw to a PDF file. This would involve creating a new Fl_Graphics_Driver derived
class. This new class should implement all virtual methods of the Fl_Graphics_Driver class
to support all FLTK drawing functions.
*/
\p The Fl_Graphics_Driver class is essential for developers of the FLTK library.
Each platform supported by FLTK requires to create a derived class of Fl_Graphics_Driver that
implements all its virtual member functions according to the platform.
*/
class FL_EXPORT Fl_Graphics_Driver {
friend class Fl_Surface_Device;
friend class Fl_Display_Device;
@ -167,22 +171,42 @@ protected:
virtual Fl_Bitmask create_bitmask(int w, int h, const uchar *array) {return 0; }
/** Support function for image drawing */
virtual void delete_bitmask(Fl_Bitmask bm) {}
/** For internal library use only */
static void change_image_size(Fl_Image *img, int W, int H) {
img->w(W);
img->h(H);
}
// Support function for image drawing
virtual void uncache_pixmap(fl_uintptr_t p);
// accessor functions to protected image members
int start_image(Fl_Image *img, int XP, int YP, int WP, int HP, int &cx, int &cy,
int &X, int &Y, int &W, int &H);
/** Accessor to a private member variable of Fl_RGB_Image */
static fl_uintptr_t* id(Fl_RGB_Image *rgb) {return &(rgb->id_);}
/** Accessor to a private member variable of Fl_Pixmap */
static fl_uintptr_t* id(Fl_Pixmap *pm) {return &(pm->id_);}
/** Accessor to a private member variable of Fl_Bitmap */
static fl_uintptr_t* id(Fl_Bitmap *bm) {return &(bm->id_);}
/** Accessor to a private member variable of Fl_RGB_Image */
static fl_uintptr_t* mask(Fl_RGB_Image *rgb) {return &(rgb->mask_);}
/** Accessor to a private member variable of Fl_Pixmap */
static fl_uintptr_t* mask(Fl_Pixmap *pm) {return &(pm->mask_);}
/** Accessor to a private member variable of Fl_Pixmap */
static float* cache_scale(Fl_Pixmap *pm) {return &(pm->cache_scale_);}
/** Accessor to a private member variable of Fl_Bitmap */
static float* cache_scale(Fl_Bitmap *bm) {return &(bm->cache_scale_);}
/** Accessor to a private member variable of Fl_RGB_Image */
static float* cache_scale(Fl_RGB_Image *rgb) {return &(rgb->cache_scale_);}
/** Accessor to a private member variable of Fl_Pixmap */
static Fl_Color* pixmap_bg_color(Fl_Pixmap *pm) {return &(pm->pixmap_bg_color);}
/** For internal library use only */
static void draw_empty(Fl_Image* img, int X, int Y) {img->draw_empty(X, Y);}
/** Accessor to a private member function of Fl_Bitmap */
static int prepare(Fl_Bitmap *bm, int XP, int YP, int WP, int HP, int &cx, int &cy,
int &X, int &Y, int &W, int &H) {
return bm->prepare(XP,YP,WP,HP,cx,cy,X,Y,W,H);
}
/** Accessor to a private member function of Fl_Pixmap */
static int prepare(Fl_Pixmap *pm, int XP, int YP, int WP, int HP, int &cx, int &cy,
int &X, int &Y, int &W, int &H) {
return pm->prepare(XP,YP,WP,HP,cx,cy,X,Y,W,H);
@ -245,8 +269,6 @@ public:
virtual void pop_matrix();
virtual void mult_matrix(double a, double b, double c, double d, double x, double y);
virtual void rotate(double d);
virtual void scale(double x, double y);
virtual void scale(double x);
virtual void translate(double x,double y);
virtual void begin_points();
virtual void begin_line();
@ -346,17 +368,134 @@ public:
virtual void add_rectangle_to_region(Fl_Region r, int x, int y, int w, int h);
virtual Fl_Region XRectangleRegion(int x, int y, int w, int h);
virtual void XDestroyRegion(Fl_Region r);
// font support
/** Returns the current value of the scaling factor (usually > 1 on HiDPI displays) */
virtual float scale() {return 1;}
/** Sets the current value of the scaling factor */
virtual void scale(float f) {}
/** Support for Fl::get_font_name() */
virtual const char* get_font_name(Fl_Font fnum, int* ap) {return NULL;}
/** Support for Fl::get_font_sizes() */
virtual int get_font_sizes(Fl_Font fnum, int*& sizep) {return 0;}
/** Support for Fl::set_fonts() */
virtual Fl_Font set_fonts(const char *name) {return 0;}
// an implementation which returns NULL may be enough
/** Some platforms may need to implement this to support fonts */
virtual Fl_Fontdesc* calc_fl_fonts(void) {return NULL;}
/** Support for Fl::set_font() */
virtual unsigned font_desc_size() {return 0;}
/** Support for Fl::get_font() */
virtual const char *font_name(int num) {return NULL;}
/** Support for Fl::set_font() */
virtual void font_name(int num, const char *name) {}
};
#ifndef FL_DOXYGEN
/* Abstract class Fl_Scalable_Graphics_Driver is platform-independent.
It supports the scaling of all graphics coordinates by a
float factor helpful to support HiDPI displays.
This class does :
- compute scaled coordinates
- scale the cached offscreen of image objects
- scale the pixel arrays used when performing direct image draws
- call the member functions of a platform-specific,
Fl_Scalable_Graphics_Driver-derived class that do the drawings with adequately
scaled coordinates. The member functions are named with the _unscaled suffix.
- scale and unscale the clipping region.
This class is presently used on the X11 platform to support HiDPI displays.
In the future, it may also be used on the WIN32 platform.
*/
class Fl_Scalable_Graphics_Driver : public Fl_Graphics_Driver {
public:
Fl_Scalable_Graphics_Driver();
float scale() { return scale_; }
protected:
float scale_; // scale between user and graphical coordinates: graphical = user * scale_
void cache_size(Fl_Image *img, int &width, int &height);
virtual Fl_Region scale_clip(float f)=0;
void unscale_clip(Fl_Region r);
virtual void draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy);
virtual void draw_unscaled(Fl_Pixmap *pxm, float s, int XP, int YP, int WP, int HP, int cx, int cy)=0;
virtual void draw(Fl_Bitmap *bm, int XP, int YP, int WP, int HP, int cx, int cy);
virtual void draw_unscaled(Fl_Bitmap *bm, float s, int XP, int YP, int WP, int HP, int cx, int cy)=0;
virtual void draw(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy);
virtual void draw_unscaled(Fl_RGB_Image *img, float s, int XP, int YP, int WP, int HP, int cx, int cy)=0;
void draw(Fl_Shared_Image *shared, int X, int Y);
virtual void point(int x, int y);
virtual void point_unscaled(float x, float y) = 0;
virtual void rect(int x, int y, int w, int h);
virtual void rect_unscaled(float x, float y, float w, float h) = 0;
virtual void rectf(int x, int y, int w, int h);
virtual void rectf_unscaled(float x, float y, float w, float h) = 0;
virtual void line(int x, int y, int x1, int y1);
virtual void line_unscaled(float x, float y, float x1, float y1) = 0;
virtual void line(int x, int y, int x1, int y1, int x2, int y2);
virtual void line_unscaled(float x, float y, float x1, float y1, float x2, float y2) = 0;
virtual void xyline(int x, int y, int x1);
virtual void xyline(int x, int y, int x1, int y2);
virtual void xyline(int x, int y, int x1, int y2, int x3);
virtual void xyline_unscaled(float x, float y, float x1)=0;
virtual void xyline_unscaled(float x, float y, float x1, float y2)=0;
virtual void xyline_unscaled(float x, float y, float x1, float y2, float x3)=0;
virtual void yxline(int x, int y, int y1);
virtual void yxline(int x, int y, int y1, int x2);
virtual void yxline(int x, int y, int y1, int x2, int y3);
virtual void yxline_unscaled(float x, float y, float y1)=0;
virtual void yxline_unscaled(float x, float y, float y1, float x2)=0;
virtual void yxline_unscaled(float x, float y, float y1, float x2, float y3)=0;
virtual void loop(int x0, int y0, int x1, int y1, int x2, int y2);
virtual void loop_unscaled(float x0, float y0, float x1, float y1, float x2, float y2)=0;
virtual void loop(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3);
virtual void loop_unscaled(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3)=0;
virtual void polygon(int x0, int y0, int x1, int y1, int x2, int y2);
virtual void polygon_unscaled(float x0, float y0, float x1, float y1, float x2, float y2)=0;
virtual void polygon(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3);
virtual void polygon_unscaled(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3)=0;
virtual void circle(double x, double y, double r);
virtual void ellipse_unscaled(double xt, double yt, double rx, double ry)=0;
virtual void font(Fl_Font face, Fl_Fontsize size);
virtual void font_unscaled(Fl_Font face, Fl_Fontsize size)=0;
virtual double width(const char *str, int n);
virtual double width(unsigned int c);
virtual double width_unscaled(const char *str, int n)=0;
virtual double width_unscaled(unsigned int c)=0;
virtual Fl_Fontsize size();
virtual Fl_Fontsize size_unscaled()=0;
virtual void text_extents(const char *str, int n, int &dx, int &dy, int &w, int &h);
virtual void text_extents_unscaled(const char *str, int n, int &dx, int &dy, int &w, int &h)=0;
virtual int height();
virtual int descent();
virtual int height_unscaled()=0;
virtual int descent_unscaled()=0;
virtual void draw(const char *str, int n, int x, int y);
virtual void draw_unscaled(const char *str, int n, int x, int y)=0;
virtual void draw(int angle, const char *str, int n, int x, int y);
virtual void draw_unscaled(int angle, const char *str, int n, int x, int y)=0;
virtual void rtl_draw(const char* str, int n, int x, int y);
virtual void rtl_draw_unscaled(const char* str, int n, int x, int y)=0;
virtual void arc(int x, int y, int w, int h, double a1, double a2);
virtual void arc_unscaled(float x, float y, float w, float h, double a1, double a2)=0;
virtual void pie(int x, int y, int w, int h, double a1, double a2);
virtual void pie_unscaled(float x, float y, float w, float h, double a1, double a2)=0;
virtual void line_style(int style, int width=0, char* dashes=0);
virtual void line_style_unscaled(int style, float width, char* dashes)=0;
virtual void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy);
virtual void copy_offscreen_unscaled(float x, float y, float w, float h, Fl_Offscreen pixmap, float srcx, float srcy)=0;
void draw_image_rescale(void *buf, Fl_Draw_Image_Cb cb, int X, int Y, int W, int H, int D, int L, bool mono, float s);
virtual void draw_image_unscaled(const uchar* buf, int X,int Y,int W,int H, int D=3, int L=0)=0;
virtual void draw_image_unscaled(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=3)=0;
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);
virtual void draw_image_mono_unscaled(const uchar* buf, int x, int y, int w, int h, int d, int l)=0;
void draw_image_mono(const uchar* buf, int X,int Y,int W,int H, int D=1, int L=0);
virtual void draw_image_mono_unscaled(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=1)=0;
void draw_image_mono(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=1);
void transformed_vertex(double xf, double yf);
virtual void transformed_vertex0(float x, float y)=0;
void vertex(double x, double y);
};
#endif // FL_DOXYGEN
#endif // FL_GRAPHICS_DRIVER_H
//

View File

@ -3,7 +3,7 @@
//
// Image header file for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2016 by Bill Spitzak and others.
// Copyright 1998-2017 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
@ -223,6 +223,7 @@ private:
// These two variables are used to cache the image and mask for the main display graphics driver
fl_uintptr_t id_;
fl_uintptr_t mask_;
float cache_scale_; // graphics scaling value when id_ was computed
public:

View File

@ -3,7 +3,7 @@
//
// Pixmap header file for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2012 by Bill Spitzak and others.
// Copyright 1998-2017 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
@ -56,6 +56,7 @@ private:
fl_uintptr_t id_;
fl_uintptr_t mask_;
Fl_Color pixmap_bg_color;
float cache_scale_; // graphics scaling value when id_ was computed
public:

View File

@ -3,7 +3,7 @@
//
// All screen related calls in a driver style class.
//
// Copyright 1998-2016 by Bill Spitzak and others.
// Copyright 1998-2017 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
@ -54,6 +54,8 @@ protected:
static const int MAX_SCREENS = 16;
int num_screens;
static float fl_intersection(int x1, int y1, int w1, int h1,
int x2, int y2, int w2, int h2);
public:
static char bg_set;
@ -61,6 +63,8 @@ public:
static char fg_set;
public:
virtual float scale(int n) {return 1;}
virtual void scale(int n, float f) { }
static Fl_Screen_Driver *newScreenDriver();
// --- display management
virtual void display(const char *disp);
@ -157,6 +161,21 @@ public:
virtual void close_display() {}
// compute dimensions of an Fl_Offscreen
virtual void offscreen_size(Fl_Offscreen off, int &width, int &height) {}
void rescale_all_windows_from_screen(int screen, float f);
static void transient_scale_display(float f, int nscreen);
static int scale_handler(int event);
virtual void init_workarea() {}
virtual float desktop_scale_factor() {return 1;}
float default_scale_factor();
enum APP_SCALING_CAPABILITY {
NO_APP_SCALING = 0, ///< The platform does not support rescaling.
SYSTEMWIDE_APP_SCALING, ///< The platform supports rescaling with the same factor for all screens.
PER_SCREEN_APP_SCALING ///< The platform supports rescaling with one factor for each screen.
};
/** Returns the platform's support for rescaling the application with ctrl-/+/-/0/ keys.
*/
virtual APP_SCALING_CAPABILITY rescalable() { return NO_APP_SCALING; }
};

View File

@ -4,7 +4,7 @@
// A base class for platform specific window handling code
// for the Fast Light Tool Kit (FLTK).
//
// Copyright 2010-2016 by Bill Spitzak and others.
// Copyright 2010-2017 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
@ -56,6 +56,8 @@ public:
static Fl_Window_Driver *newWindowDriver(Fl_Window *);
int wait_for_expose_value;
Fl_Offscreen other_xid; // offscreen bitmap (overlay and double-buffered windows)
virtual int screen_num();
virtual void screen_num(int) {}
// --- frequently used accessors to public window data
/** returns the x coordinate of the window. */

View File

@ -3,7 +3,7 @@
//
// Portable drawing function header file for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2016 by Bill Spitzak and others.
// Copyright 1998-2017 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
@ -335,12 +335,16 @@ inline void fl_pop_matrix() { fl_graphics_driver->pop_matrix(); }
Concatenates scaling transformation onto the current one.
\param[in] x,y scale factors in x-direction and y-direction
*/
inline void fl_scale(double x, double y) { fl_graphics_driver->scale(x, y); }
inline void fl_scale(double x, double y) {
fl_graphics_driver->mult_matrix(x,0,0,y,0,0);
}
/**
Concatenates scaling transformation onto the current one.
\param[in] x scale factor in both x-direction and y-direction
*/
inline void fl_scale(double x) { fl_graphics_driver->scale(x, x); }
inline void fl_scale(double x) {
fl_graphics_driver->mult_matrix(x,0,0,x,0,0);
}
/**
Concatenates translation transformation onto the current one.
\param[in] x,y translation factor in x-direction and y-direction

View File

@ -3,7 +3,7 @@
//
// Main event handling code for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2016 by Bill Spitzak and others.
// Copyright 1998-2017 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
@ -1978,6 +1978,19 @@ void Fl::disable_im()
void fl_open_display()
{
Fl::screen_driver()->open_display();
static bool been_here = false;
if (!been_here) {
been_here = true;
Fl_Screen_Driver *dr = Fl::screen_driver();
if (dr->rescalable()) {
float factor = dr->default_scale_factor();
for (int i = 0; i < dr->screen_count(); i++) dr->scale(i, factor);
#if defined(FLTK_HIDPI_SUPPORT) || !(defined(WIN32) || defined(__APPLE__))
Fl::add_handler(Fl_Screen_Driver::scale_handler);
#endif
Fl_Graphics_Driver::default_driver().scale(factor);
}
}
}
void fl_close_display()

View File

@ -3,7 +3,7 @@
//
// OpenGL window code for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2016 by Bill Spitzak and others.
// Copyright 1998-2017 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
@ -601,12 +601,19 @@ char Fl_Cocoa_Gl_Window_Driver::swap_type() {return COPY;}
#include "drivers/WinAPI/Fl_WinAPI_Window_Driver.H"
#include <FL/x.H>
#include <FL/Fl_Graphics_Driver.H>
#include <FL/Fl_Screen_Driver.H>
Fl_Gl_Window_Driver *Fl_Gl_Window_Driver::newGlWindowDriver(Fl_Gl_Window *w)
{
return new Fl_WinAPI_Gl_Window_Driver(w);
}
float Fl_WinAPI_Gl_Window_Driver::pixels_per_unit()
{
return Fl::screen_driver()->scale(0);
}
int Fl_WinAPI_Gl_Window_Driver::mode_(int m, const int *a) {
int oldmode = mode();
pWindow->context(0);
@ -685,6 +692,8 @@ void* Fl_WinAPI_Gl_Window_Driver::GetProcAddress(const char *procName) {
#if defined(FL_CFG_GFX_XLIB)
#include <FL/x.H>
#include "Fl_Gl_Choice.H"
#include <FL/Fl_Screen_Driver.H>
#include <FL/Fl_Window_Driver.H>
Fl_Gl_Window_Driver *Fl_Gl_Window_Driver::newGlWindowDriver(Fl_Gl_Window *w)
{
@ -696,6 +705,12 @@ void Fl_X11_Gl_Window_Driver::before_show(int& need_redraw) {
if (overlay() && overlay() != pWindow) ((Fl_Gl_Window*)overlay())->show();
}
float Fl_X11_Gl_Window_Driver::pixels_per_unit()
{
int ns = pWindow->driver()->screen_num();
return Fl::screen_driver()->scale(ns);
}
int Fl_X11_Gl_Window_Driver::mode_(int m, const int *a) {
int oldmode = mode();
if (a) { // when the mode is set using the a array of system-dependent values, and if asking for double buffer,

View File

@ -3,7 +3,7 @@
//
// implementation of Fl_Graphics_Driver class for the Fast Light Tool Kit (FLTK).
//
// Copyright 2010-2016 by Bill Spitzak and others.
// Copyright 2010-2017 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
@ -23,6 +23,7 @@
#include <FL/Fl_Image.H>
#include <FL/fl_draw.H>
#include <FL/Fl_Image_Surface.H>
#include <FL/math.h>
FL_EXPORT Fl_Graphics_Driver *fl_graphics_driver; // the current driver of graphics operations
@ -181,6 +182,349 @@ void Fl_Graphics_Driver::uncache_pixmap(fl_uintptr_t p) {
fl_delete_offscreen((Fl_Offscreen)p);
}
#ifndef FL_DOXYGEN
Fl_Scalable_Graphics_Driver::Fl_Scalable_Graphics_Driver() : Fl_Graphics_Driver() {
scale_ = 1;
}
void Fl_Scalable_Graphics_Driver::rect(int x, int y, int w, int h)
{
rect_unscaled(x * scale_, y * scale_, w * scale_, h * scale_);
}
void Fl_Scalable_Graphics_Driver::rectf(int x, int y, int w, int h)
{
rectf_unscaled(x * scale_, y * scale_, w * scale_, h * scale_);
}
void Fl_Scalable_Graphics_Driver::point(int x, int y) {
point_unscaled(x * scale_, y * scale_);
}
void Fl_Scalable_Graphics_Driver::line(int x, int y, int x1, int y1) {
line_unscaled( x*scale_, y*scale_, x1*scale_, y1*scale_);
}
void Fl_Scalable_Graphics_Driver::line(int x, int y, int x1, int y1, int x2, int y2) {
line_unscaled( x*scale_, y*scale_, x1*scale_, y1*scale_, x2*scale_, y2*scale_);
}
void Fl_Scalable_Graphics_Driver::xyline(int x, int y, int x1) {
xyline_unscaled(x*scale_, y*scale_, x1*scale_);
}
void Fl_Scalable_Graphics_Driver::xyline(int x, int y, int x1, int y2) {
xyline_unscaled(x*scale_, y*scale_, x1*scale_, y2*scale_);
}
void Fl_Scalable_Graphics_Driver::xyline(int x, int y, int x1, int y2, int x3) {
xyline_unscaled(x*scale_, y*scale_, x1*scale_, y2*scale_, x3*scale_);
}
void Fl_Scalable_Graphics_Driver::yxline(int x, int y, int y1) {
yxline_unscaled(x*scale_, y*scale_, y1*scale_);
}
void Fl_Scalable_Graphics_Driver::yxline(int x, int y, int y1, int x2) {
yxline_unscaled(x*scale_, y*scale_, y1*scale_, x2*scale_);
}
void Fl_Scalable_Graphics_Driver::yxline(int x, int y, int y1, int x2, int y3) {
yxline_unscaled(x*scale_, y*scale_, y1*scale_, x2*scale_, y3*scale_);
}
void Fl_Scalable_Graphics_Driver::loop(int x0, int y0, int x1, int y1, int x2, int y2) {
loop_unscaled(x0*scale_, y0*scale_, x1*scale_, y1*scale_, x2*scale_, y2*scale_);
}
void Fl_Scalable_Graphics_Driver::loop(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) {
loop_unscaled(x0*scale_, y0*scale_, x1*scale_, y1*scale_, x2*scale_, y2*scale_, x3*scale_, y3*scale_);
}
void Fl_Scalable_Graphics_Driver::polygon(int x0, int y0, int x1, int y1, int x2, int y2) {
polygon_unscaled(x0*scale_, y0*scale_, x1*scale_, y1*scale_, x2*scale_, y2*scale_);
}
void Fl_Scalable_Graphics_Driver::polygon(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3) {
polygon_unscaled(x0*scale_, y0*scale_, x1*scale_, y1*scale_, x2*scale_, y2*scale_, x3*scale_, y3*scale_);
}
void Fl_Scalable_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));
ellipse_unscaled(xt*scale_, yt*scale_, rx*scale_, ry*scale_);
}
// compute width & height of cached image so it can be tiled without undrawn gaps when scaling output
void Fl_Scalable_Graphics_Driver::cache_size(Fl_Image *img, int &width, int &height)
{
if ( int(scale_) == scale_ ) {
width = width * scale_;
height = height * scale_;
} else {
width = (width+1) * scale_;
height = (height+1) * scale_;
}
}
void Fl_Scalable_Graphics_Driver::draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) {
int X, Y, W, H;
if (Fl_Graphics_Driver::start_image(pxm, XP, YP, WP, HP, cx, cy, X, Y, W, H)) {
return;
}
// to allow rescale at runtime
if (*id(pxm)) {
if (*cache_scale(pxm) != scale_) {
pxm->uncache();
}
}
if (!*id(pxm)) {
if (scale_ != 1) { // build a scaled id_ & pixmap_ for pxm
int w2=pxm->w(), h2=pxm->h();
cache_size(pxm, w2, h2);
Fl_Pixmap *pxm2 = (Fl_Pixmap*)pxm->copy(w2, h2);
float s = scale_; scale_ = 1;
*id(pxm) = cache(pxm2, pxm2->w(), pxm2->h(), pxm2->data());
scale_ = s;
*cache_scale(pxm) = scale_;
*mask(pxm) = *mask(pxm2);
*mask(pxm2) = 0;
delete pxm2;
} else *id(pxm) = cache(pxm, pxm->w(), pxm->h(), pxm->data());
}
// draw pxm using its scaled id_ & pixmap_
draw_unscaled(pxm, scale_, X, Y, W, H, cx, cy);
}
void Fl_Scalable_Graphics_Driver::draw(Fl_Bitmap *bm, int XP, int YP, int WP, int HP, int cx, int cy) {
int X, Y, W, H;
if (Fl_Graphics_Driver::start_image(bm, XP, YP, WP, HP, cx, cy, X, Y, W, H)) {
return;
}
if (*id(bm)) {
if (*cache_scale(bm) != scale_) {
bm->uncache();
}
}
if (!*id(bm)) {
if (scale_ != 1) { // build a scaled id_ for bm
int w2 = bm->w(), h2 = bm->h();
cache_size(bm, w2, h2);
Fl_Bitmap *bm2 = (Fl_Bitmap*)bm->copy(w2, h2);
*id(bm) = cache(bm2, bm2->w(), bm2->h(), bm2->array);
*cache_scale(bm) = scale_;
delete bm2;
} else *id(bm) = cache(bm, bm->w(), bm->h(), bm->array);
}
// draw bm using its scaled id_
draw_unscaled(bm, scale_, X, Y, W, H, cx, cy);
}
void Fl_Scalable_Graphics_Driver::draw(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy) {
// Don't draw an empty image...
if (!img->d() || !img->array) {
Fl_Graphics_Driver::draw_empty(img, XP, YP);
return;
}
if (start_image(img, XP, YP, WP, HP, cx, cy, XP, YP, WP, HP)) {
return;
}
if (scale() != 1 && can_do_alpha_blending()) { // try and use the system's scaled image drawing
push_clip(XP, YP, WP, HP);
Fl_Region r = scale_clip(scale_);
int done = draw_scaled(img, XP-cx, YP-cy, img->w(), img->h());
unscale_clip(r);
pop_clip();
if (done) return;
}
// to allow rescale at runtime
if (*id(img) && *cache_scale(img) != scale_) {
img->uncache();
}
if (!*id(img) && scale_ != 1) { // build and draw a scaled id_ for img
int w2=img->w(), h2=img->h();
cache_size(img, w2, h2);
Fl_RGB_Image *img2 = (Fl_RGB_Image*)img->copy(w2, h2);
draw_unscaled(img2, scale_, XP, YP, WP, HP, cx, cy);
*id(img) = *id(img2);
*id(img2) = 0;
*cache_scale(img) = scale_;
delete img2;
}
else { // draw img using its scaled id_
draw_unscaled(img, scale_, XP, YP, WP, HP, cx, cy);
}
}
void Fl_Scalable_Graphics_Driver::draw(Fl_Shared_Image *shared, int X, int Y) {
if (scale_ == 1) {
Fl_Graphics_Driver::draw(shared, X, Y);
return;
}
float s = scale_; scale_ = 1;
Fl_Region r2 = scale_clip(s);
int oldw=shared->w();
int oldh=shared->h();
change_image_size(shared, (oldw*s < 1 ? 1: int(oldw*s)), (oldh*s < 1 ? 1: int(oldh*s)));
Fl_Graphics_Driver::draw(shared, X*s, Y*s);
change_image_size(shared, oldw, oldh);
unscale_clip(r2);
scale_ = s;
}
void Fl_Scalable_Graphics_Driver::font(Fl_Font face, Fl_Fontsize size) {
font_unscaled(face, size * scale_);
}
double Fl_Scalable_Graphics_Driver::width(const char *str, int n) {
return width_unscaled(str, n)/scale_;
}
double Fl_Scalable_Graphics_Driver::width(unsigned int c) {
return width_unscaled(c)/scale_;
}
Fl_Fontsize Fl_Scalable_Graphics_Driver::size() {
if (!font_descriptor() ) return -1;
return size_unscaled()/scale_;
}
void Fl_Scalable_Graphics_Driver::text_extents(const char *str, int n, int &dx, int &dy, int &w, int &h) {
text_extents_unscaled(str, n, dx, dy, w, h);
dx /= scale_;
dy /= scale_;
w /= scale_;
h /= scale_;
}
int Fl_Scalable_Graphics_Driver::height() {
return int(height_unscaled()/scale_);
}
int Fl_Scalable_Graphics_Driver::descent() {
return descent_unscaled()/scale_;
}
void Fl_Scalable_Graphics_Driver::draw(const char *str, int n, int x, int y) {
if (!size_ || !font_descriptor()) font(FL_HELVETICA, FL_NORMAL_SIZE);
Fl_Region r2 = scale_clip(scale_);
draw_unscaled(str, n, x*scale_, y*scale_);
unscale_clip(r2);
}
void Fl_Scalable_Graphics_Driver::draw(int angle, const char *str, int n, int x, int y) {
if (!size_ || !font_descriptor()) font(FL_HELVETICA, FL_NORMAL_SIZE);
Fl_Region r2 = scale_clip(scale_);
draw_unscaled(angle, str, n, x*scale_, y*scale_);
unscale_clip(r2);
}
void Fl_Scalable_Graphics_Driver::rtl_draw(const char* str, int n, int x, int y) {
rtl_draw_unscaled(str, n, x * scale_, y * scale_);
}
void Fl_Scalable_Graphics_Driver::arc(int x,int y,int w,int h,double a1,double a2) {
arc_unscaled(x * scale_, y * scale_, w * scale_, h * scale_, a1, a2);
}
void Fl_Scalable_Graphics_Driver::pie(int x,int y,int w,int h,double a1,double a2) {
pie_unscaled(x * scale_, y * scale_, w * scale_, h * scale_, a1, a2);
}
void Fl_Scalable_Graphics_Driver::line_style(int style, int width, char* dashes) {
line_style_unscaled(style, width * scale_, dashes);
}
void Fl_Scalable_Graphics_Driver::copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy) {
copy_offscreen_unscaled(x * scale_, y * scale_, w * scale_, h * scale_, pixmap, srcx * scale_, srcy * scale_);
}
/* read the image data from a pointer or with a callback, scale it, and draw it */
void Fl_Scalable_Graphics_Driver::draw_image_rescale(void *buf, Fl_Draw_Image_Cb cb,
int X, int Y, int W, int H, int D, int L, bool mono, float s) {
int aD = abs(D);
if (L == 0) L = W*aD;
int depth = mono ? (aD%2==0?2:1) : aD;
uchar *tmp_buf = new uchar[W*H*depth];
if (cb) {
for (int i = 0; i < H; i++) {
cb(buf, 0, i, W, tmp_buf + i * W * depth);
}
} else {
uchar *q, *p = tmp_buf;
for (int i = 0; i < H; i++) {
q = (uchar*)buf + i * L;
for (int j = 0; j < W; j++) {
memcpy(p, q, depth);
p += depth; q += D;
}
}
}
Fl_RGB_Image *rgb = new Fl_RGB_Image(tmp_buf, W, H, depth);
rgb->alloc_array = 1;
Fl_RGB_Image *scaled_rgb = (Fl_RGB_Image*)rgb->copy(ceil(W * s), ceil(H * s));
delete rgb;
if (scaled_rgb) {
Fl_Region r2 = scale_clip(s);
draw_image_unscaled(scaled_rgb->array, X * s, Y * s, scaled_rgb->w(), scaled_rgb->h(), depth);
unscale_clip(r2);
delete scaled_rgb;
}
}
void Fl_Scalable_Graphics_Driver::draw_image(const uchar* buf, int X,int Y,int W,int H, int D, int L) {
if (scale_ == 1) {
draw_image_unscaled(buf, X,Y,W,H,D,L);
} else {
draw_image_rescale((void*)buf, NULL, X, Y, W, H, D, L, false, scale_);
}
}
void Fl_Scalable_Graphics_Driver::draw_image(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D) {
if (scale_ == 1) {
draw_image_unscaled(cb, data, X,Y,W,H,D);
} else {
draw_image_rescale(data, cb, X, Y, W, H, D, 0, false, scale_);
}
}
void Fl_Scalable_Graphics_Driver::draw_image_mono(const uchar* buf, int X,int Y,int W,int H, int D, int L) {
if (scale_ == 1) {
draw_image_mono_unscaled(buf, X,Y,W,H,D,L);
} else {
draw_image_rescale((void*)buf, NULL, X, Y, W, H, D, L, true, scale_);
}
}
void Fl_Scalable_Graphics_Driver::draw_image_mono(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D) {
if (scale_ == 1) {
draw_image_mono_unscaled(cb, data, X,Y,W,H,D);
} else {
draw_image_rescale(data, cb, X, Y, W, H, D, 0, true, scale_);
}
}
void Fl_Scalable_Graphics_Driver::transformed_vertex(double xf, double yf) {
transformed_vertex0(xf * scale_, yf * scale_);
}
void Fl_Scalable_Graphics_Driver::vertex(double x,double y) {
transformed_vertex0((x*m.a + y*m.c + m.x) * scale_, (x*m.b + y*m.d + m.y) * scale_);
}
void Fl_Scalable_Graphics_Driver::unscale_clip(Fl_Region r) {
if (r) {
if (rstack[rstackptr]) XDestroyRegion(rstack[rstackptr]);
rstack[rstackptr] = r;
}
}
#endif // !FL_DOXYGEN
//
// End of "$Id$".
//

View File

@ -3,7 +3,7 @@
//
// Image drawing code for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2015 by Bill Spitzak and others.
// Copyright 1998-2017 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
@ -271,7 +271,8 @@ Fl_RGB_Image::Fl_RGB_Image(const uchar *bits, int W, int H, int D, int LD) :
array(bits),
alloc_array(0),
id_(0),
mask_(0)
mask_(0),
cache_scale_(1)
{
data((const char **)&array, 1);
ld(LD);
@ -293,7 +294,8 @@ Fl_RGB_Image::Fl_RGB_Image(const Fl_Pixmap *pxm, Fl_Color bg):
array(0),
alloc_array(0),
id_(0),
mask_(0)
mask_(0),
cache_scale_(1)
{
if (pxm && pxm->w() > 0 && pxm->h() > 0) {
array = new uchar[w() * h() * d()];

View File

@ -3,7 +3,7 @@
//
// Draw-to-image code for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2016 by Bill Spitzak and others.
// Copyright 1998-2017 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
@ -17,6 +17,7 @@
//
#include <FL/Fl_Image_Surface.H>
#include <FL/Fl_Device.H>
#if defined(FL_PORTING)
# pragma message "FL_PORTING: optionally implement class Fl_XXX_Image_Surface_Driver for your platform"
@ -97,7 +98,7 @@ Fl_Shared_Image* Fl_Image_Surface::highres_image()
Fl_Shared_Image *s_img = Fl_Shared_Image::get(platform_surface->image());
int width, height;
platform_surface->printable_rect(&width, &height);
s_img->scale(width, height);
s_img->scale(width, height, 1, 1);
return s_img;
}
@ -138,7 +139,9 @@ static int find_slot(void) { // return an available slot to memorize an Fl_Image
*/
Fl_Offscreen fl_create_offscreen(int w, int h) {
int rank = find_slot();
offscreen_api_surface[rank] = new Fl_Image_Surface(w, h, 0);
float d = Fl_Graphics_Driver::default_driver().scale();
int high_res = d != 1;
offscreen_api_surface[rank] = new Fl_Image_Surface(w, h, high_res);
return offscreen_api_surface[rank]->offscreen();
}

View File

@ -3,7 +3,7 @@
//
// Pixmap drawing code for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2015 by Bill Spitzak and others.
// Copyright 1998-2017 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
@ -42,6 +42,7 @@ void Fl_Pixmap::measure() {
if (w()<0 && data()) {
fl_measure_pixmap(data(), W, H);
w(W); h(H);
cache_scale_ = 1;
}
}

View File

@ -3,7 +3,7 @@
//
// All screen related calls in a driver style class.
//
// Copyright 1998-2016 by Bill Spitzak and others.
// Copyright 1998-2017 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
@ -24,6 +24,10 @@
#include <FL/Fl_Group.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Input.H>
#include <FL/Fl_Window_Driver.H>
#include <FL/Fl_Image_Surface.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_Tooltip.H>
char Fl_Screen_Driver::bg_set = 0;
char Fl_Screen_Driver::bg2_set = 0;
@ -110,7 +114,7 @@ int Fl_Screen_Driver::screen_num(int x, int y)
// Return the number of pixels common to the two rectangular areas
static inline float fl_intersection(int x1, int y1, int w1, int h1,
float Fl_Screen_Driver::fl_intersection(int x1, int y1, int w1, int h1,
int x2, int y2, int w2, int h2)
{
if(x1+w1 < x2 || x2+w2 < x1 || y1+h1 < y2 || y2+h2 < y1)
@ -154,7 +158,7 @@ void Fl_Screen_Driver::compose_reset() {
}
uchar *Fl_Screen_Driver::read_image(uchar *p, int X, int Y, int w, int h, int alpha) {
uchar *image_data;
uchar *image_data = NULL;
Fl_RGB_Image *img;
if (fl_find(fl_window) == 0) { // read from off_screen buffer
img = read_win_rectangle(p, X, Y, w, h, alpha);
@ -165,14 +169,16 @@ uchar *Fl_Screen_Driver::read_image(uchar *p, int X, int Y, int w, int h, int al
} else {
img = traverse_to_gl_subwindows(Fl_Window::current(), p, X, Y, w, h, alpha, NULL);
}
if (img->w() > w) {
Fl_RGB_Image *img2 = (Fl_RGB_Image*)img->copy(w, h);
if (img) {
if (img->w() > w) {
Fl_RGB_Image *img2 = (Fl_RGB_Image*)img->copy(w, h);
delete img;
img = img2;
}
img->alloc_array = 0;
image_data = (uchar*)img->array;
delete img;
img = img2;
}
img->alloc_array = 0;
image_data = (uchar*)img->array;
delete img;
return image_data;
}
@ -268,7 +274,9 @@ Fl_RGB_Image *Fl_Screen_Driver::traverse_to_gl_subwindows(Fl_Group *g, uchar *p,
} else {
top = full_img->h() - (origin_y - y + img->h());
}
write_image_inside(full_img, img, origin_x - x, top);
int nscreen = c->as_window()->driver()->screen_num();
float s = Fl::screen_driver()->scale(nscreen);
write_image_inside(full_img, img, (origin_x - x) * s, top * s);
delete img;
}
}
@ -346,6 +354,154 @@ int Fl_Screen_Driver::input_widget_handle_key(int key, unsigned mods, unsigned s
return -1;
}
#if defined(FLTK_HIDPI_SUPPORT) || !(defined(WIN32) || defined(__APPLE__))
void Fl_Screen_Driver::rescale_all_windows_from_screen(int screen, float f)
{
float old_f = this->scale(screen);
if (f == old_f) return;
this->scale(screen, f);
Fl_Graphics_Driver *d = Fl_Display_Device::display_device()->driver();
d->scale(f);
int i = 0, count = 0; // count top-level windows, except transient scale-displaying window
Fl_Window *win = Fl::first_window();
while (win) {
if (!win->parent() && (win->driver()->screen_num() == screen || rescalable() == SYSTEMWIDE_APP_SCALING) &&
win->user_data() != &Fl_Screen_Driver::transient_scale_display) count++;
win = Fl::next_window(win);
}
Fl_Window **win_array = new Fl_Window*[count];
win = Fl::first_window(); // memorize all top-level windows
while (win) {
if (!win->parent() && win->user_data() != &Fl_Screen_Driver::transient_scale_display &&
(win->driver()->screen_num() == screen || rescalable() == SYSTEMWIDE_APP_SCALING) ) {
win_array[i++] = win;
}
win = Fl::next_window(win);
}
for (i = count - 1; i >= 0; i--) { // rescale all top-level windows, finishing with front one
win = win_array[i];
int oldx = win->x(), oldy = win->y();
win->hide();
win->driver()->screen_num(screen);
win->position(oldx*old_f/f, oldy*old_f/f);
win->driver()->force_position(1);
if (win->fullscreen_active()) {
win->size(win->w() * old_f/f, win->h() * old_f/f);
}
win->show();
win->wait_for_expose();
}
delete[] win_array;
}
static void del_transient_window(void *data) {
Fl_Window *win = (Fl_Window*)data;
delete (Fl_RGB_Image*)win->child(0)->user_data();
Fl::delete_widget(win);
}
void Fl_Screen_Driver::transient_scale_display(float f, int nscreen)
{ // transiently show the new scaling value using a shaped window
int w = 150;
// draw a white rounded box on black background
Fl_Screen_Driver *d = Fl::screen_driver();
float s = d->scale(nscreen);
if (s > 3) s = 3; // limit the growth of the transient window
Fl_Image_Surface *surf = new Fl_Image_Surface(w*s, w*s/2);
Fl_Surface_Device::push_current(surf);
fl_color(FL_BLACK);
fl_rectf(-1, -1, w*s+2, w*s+2);
Fl_Box *b = new Fl_Box(FL_RFLAT_BOX, 0, 0, w*s, w*s/2, "");
b->color(FL_WHITE);
surf->draw(b);
delete b;
Fl_RGB_Image* img = surf->image(); // img will be the window's shape
Fl_Surface_Device::pop_current();
delete surf;
//create a window shaped with the rounded box
int X, Y, W, H;
Fl::screen_xywh(X, Y, W, H, nscreen);
w /= d->scale(nscreen)/s;
Fl_Window *win = new Fl_Window((X + W/2) -w/2, (Y + H/2) -w/4, w, w/2, 0);
b = new Fl_Box(FL_FLAT_BOX, 0, 0, w, w/2, NULL);
char str[10];
sprintf(str, "%d %%", int(f * 100 + 0.5));
b->copy_label(str);
b->labelfont(FL_TIMES_BOLD);
b->labelsize(30 * s / d->scale(nscreen));
b->labelcolor(FL_BLACK);
b->color(Fl_Tooltip::color());
win->end();
win->shape(img);
b->user_data(img);
win->user_data((void*)&transient_scale_display); // prevent this window from being rescaled later
win->set_output();
win->set_non_modal();
win->driver()->screen_num(nscreen);
win->driver()->force_position(1);
win->show();
Fl::add_timeout(1, del_transient_window, win); // delete after 1 sec
}
// respond to Ctrl-'+' and Ctrl-'-' and Ctrl-'0' (Ctrl-'=' is same as Ctrl-'+') by rescaling all windows
int Fl_Screen_Driver::scale_handler(int event)
{
if ( event != FL_SHORTCUT || (!Fl::event_command()) ) return 0;
int key = Fl::event_key() & ~(FL_SHIFT+FL_COMMAND);
if (key == '=' || key == '-' || key == '+' || key == '0' || key == 0xE0/* for '0' on Fr keyboard */) {
int i, count;
if (Fl::grab()) return 0; // don't rescale when menu windows are on
Fl_Widget *wid = Fl::focus();
if (!wid) return 0;
int screen = wid->top_window()->driver()->screen_num();
Fl_Screen_Driver *screen_dr = Fl::screen_driver();
static float initial_scale = screen_dr->scale(screen);
static float scaling_values[] = {0.5, 2.f/3, 0.8, 0.9, 1, 1.1, 1.2, 4.f/3, 1.5, 1.7, 2, 2.4, 3,
4, 5.5, 6.5, 7.5, 9.75 };
float f, old_f = screen_dr->scale(screen)/initial_scale;
if (key == '0' || key == 0xE0) f = 1;
else {
count = sizeof(scaling_values)/sizeof(float);
for (i = 0; i < count; i++) {
if (old_f >= scaling_values[i] - 1e-4 && (i+1 >= count || old_f < scaling_values[i+1] - 1e-4)) {
break;
}
}
if (key == '-') i--; else i++;
if (i < 0) i = 0; if (i >= count) i = count - 1;
f = scaling_values[i];
}
if (f == old_f) return 1;
screen_dr->rescale_all_windows_from_screen(screen, f*initial_scale);
Fl_Screen_Driver::transient_scale_display(f, screen);
screen_dr->init_workarea();
return 1;
}
return 0;
}
#endif // FLTK_HIDPI_SUPPORT
// determine the scaling value used at startup time (helps supporting HiDPI displays)
float Fl_Screen_Driver::default_scale_factor()
{
float factor = 1;
#if defined(FLTK_HIDPI_SUPPORT) || !(defined(WIN32) || defined(__APPLE__))
char *p = 0;
if ((p = getenv("FLTK_SCALING_FACTOR"))) {
sscanf(p, "%f", &factor);
}
else {
factor = desktop_scale_factor();
}
#endif // FLTK_HIDPI_SUPPORT
return factor;
}
//
// End of "$Id$".
//

View File

@ -3,7 +3,7 @@
//
// Scroll widget for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2015 by Bill Spitzak and others.
// Copyright 1998-2017 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
@ -243,7 +243,8 @@ void Fl_Scroll::draw() {
uchar d = damage();
if (d & FL_DAMAGE_ALL) { // full redraw
float scale = Fl_Surface_Device::surface()->driver()->scale();
if ((d & FL_DAMAGE_ALL) || scale != int(scale)) { // full redraw
draw_box(box(),x(),y(),w(),h(),color());
draw_clip(this, X, Y, W, H);
} else {

View File

@ -3,7 +3,7 @@
//
// Shared image code for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2016 by Bill Spitzak and others.
// Copyright 1998-2017 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
@ -366,9 +366,10 @@ void Fl_Shared_Image::draw(int X, int Y, int W, int H, int cx, int cy) {
Fl_Image::draw(X, Y, W, H, cx, cy);
return;
}
fl_push_clip(X, Y, W, H);
bool need_clip = (W != w() || H != h() || cx || cy);
if (need_clip) fl_push_clip(X, Y, W, H);
fl_graphics_driver->draw(this, X-cx, Y-cy);
fl_pop_clip();
if (need_clip) fl_pop_clip();
}
/** Draws the shared image to the current surface with its top-left at X,Y */
@ -379,7 +380,7 @@ void Fl_Graphics_Driver::draw(Fl_Shared_Image *shared, int X, int Y) {
}
// don't call Fl_Graphics_Driver::draw_scaled(Fl_Image*,...) for an enlarged Fl_Bitmap or Fl_Pixmap
if (shared->image_->as_rgb_image() || (shared->w() <= shared->image_->w() && shared->h() <= shared->image_->h())) {
int done = fl_graphics_driver->draw_scaled(shared->image_, X, Y, shared->w(), shared->h());
int done = draw_scaled(shared->image_, X, Y, shared->w(), shared->h());
if (done) return;
}
if (shared->scaled_image_ && (shared->scaled_image_->w() != shared->w() || shared->scaled_image_->h() != shared->h())) {
@ -401,7 +402,7 @@ void Fl_Graphics_Driver::draw(Fl_Shared_Image *shared, int X, int Y) {
This can be useful to draw a shared image on a drawing surface whose resolution is higher
than the drawing unit for this surface: all pixels of the original image become available to fill
an area of the drawing surface sized at <tt>width,height</tt>.
Examples of such drawing surfaces: laser printers, PostScript files, PDF printers, retina displays on Apple hardware.
Examples of such drawing surfaces: laser printers, PostScript files, PDF printers, HiDPI displays.
\param width,height maximum width and height (in drawing units) to use when drawing the shared image
\param proportional if not null, keep the width and height of the shared image proportional to those of its original image
@ -413,7 +414,7 @@ void Fl_Graphics_Driver::draw(Fl_Shared_Image *shared, int X, int Y) {
\code
Fl_Box *b = ... // a box
Fl_Shared_Image *shared = Fl_Shared_Image::get("/path/to/picture.jpeg"); // read a picture file
shared->scale(b->w(), b->h(), 1); // set the drawing size of the shared image to the size of the box
shared->scale(b->w(), b->h()); // set the drawing size of the shared image to the size of the box
b->image(shared); // use the shared image as the box image
b->align(FL_ALIGN_INSIDE | FL_ALIGN_CENTER | FL_ALIGN_CLIP); // the image is to be drawn centered in the box
\endcode

View File

@ -3,7 +3,7 @@
//
// Drivers code for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2016 by Bill Spitzak and others.
// Copyright 1998-2017 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
@ -22,6 +22,7 @@
#include <FL/x.H>
#include <FL/Fl_Shared_Image.H>
#include <FL/Fl_Window_Driver.H>
#include <FL/Fl_Screen_Driver.H>
/** The constructor.
@ -153,13 +154,19 @@ void Fl_Widget_Surface::print_window_part(Fl_Window *win, int x, int y, int w, i
Fl_Window *save_front = Fl::first_window();
win->show();
Fl::check();
win->driver()->flush(); // makes the window current necessary for fl_read_image
uchar *image_data;
image_data = fl_read_image(NULL, x, y, w, h);
win->driver()->flush(); // makes the window current
const uchar *image_data;
Fl_RGB_Image *img = Fl_Screen_Driver::traverse_to_gl_subwindows(win, NULL, x, y, w, h, 0, NULL);
if (img->w() > w) {
Fl_RGB_Image *img2 = (Fl_RGB_Image*)img->copy(w, h);
delete img;
img = img2;
}
image_data = img->array;
if (save_front != win) save_front->show();
set_current();
fl_draw_image(image_data, delta_x, delta_y, w, h, 3);
delete[] image_data;
delete img;
}
/**

View File

@ -4,7 +4,7 @@
// A base class for platform specific window handling code
// for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2016 by Bill Spitzak and others.
// Copyright 1998-2017 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
@ -247,6 +247,11 @@ void Fl_Window_Driver::wait_for_expose() {
}
}
int Fl_Window_Driver::screen_num() {
if (pWindow->parent()) return pWindow->top_window()->driver()->screen_num();
return Fl::screen_num(x(), y(), w(), h());
}
//
// End of "$Id$".
//

View File

@ -56,6 +56,7 @@ void fl_cleanup_dc_list(void);
#include "drivers/WinAPI/Fl_WinAPI_Window_Driver.H"
#include "drivers/WinAPI/Fl_WinAPI_System_Driver.H"
#include "drivers/WinAPI/Fl_WinAPI_Screen_Driver.H"
#include "drivers/GDI/Fl_GDI_Graphics_Driver.H"
#include <FL/fl_utf8.h>
#include <FL/Fl_Window.H>
#include <FL/fl_draw.H>
@ -489,6 +490,8 @@ int Fl_WinAPI_Screen_Driver::ready() {
return get_wsock_mod() ? s_wsock_select(0,&fdt[0],&fdt[1],&fdt[2],&t) : 0;
}
//FILE *LOG=fopen("log.log","w");
void Fl_WinAPI_Screen_Driver::open_display() {
static char beenHereDoneThat = 0;
@ -496,12 +499,43 @@ void Fl_WinAPI_Screen_Driver::open_display() {
return;
beenHereDoneThat = 1;
#ifdef FLTK_HIDPI_SUPPORT
typedef HRESULT WINAPI (*SetProcessDpiAwareness_type)(int);
HMODULE hMod = LoadLibrary("Shcore.DLL");
if (hMod) {
SetProcessDpiAwareness_type fl_SetProcessDpiAwareness = (SetProcessDpiAwareness_type)GetProcAddress(hMod, "SetProcessDpiAwareness");
HRESULT r = 0;
const int PROCESS_PER_MONITOR_DPI_AWARE = 2;
if (fl_SetProcessDpiAwareness) r = fl_SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
//fprintf(LOG,"SetProcessDpiAwareness=%p result=%d\n",fl_SetProcessDpiAwareness,r);fflush(LOG);
}
#endif // FLTK_HIDPI_SUPPORT
OleInitialize(0L);
get_imm_module();
}
float Fl_WinAPI_Screen_Driver::desktop_scale_factor() {
typedef HRESULT WINAPI (*GetDpiForMonitor_type)(HMONITOR, int, UINT*, UINT*);
float f = 1;
#ifdef FLTK_HIDPI_SUPPORT
HMODULE hMod = LoadLibrary("Shcore.DLL");
GetDpiForMonitor_type fl_GetDpiForMonitor = NULL;
if (hMod) fl_GetDpiForMonitor = (GetDpiForMonitor_type)GetProcAddress(hMod, "GetDpiForMonitor");
if (fl_GetDpiForMonitor) {
RECT rect = {0, 0, 0, 0};
HMONITOR hm = MonitorFromRect(&rect, MONITOR_DEFAULTTOPRIMARY);
UINT dpiX, dpiY;
HRESULT r = fl_GetDpiForMonitor(hm, 0, &dpiX, &dpiY);
if (r == S_OK) f = dpiX/96.;
//fprintf(LOG, "result=%d dpiX=%d dpiY=%d factor=%.2f\n", r, dpiX, dpiY, f);fflush(LOG);
}
#endif // FLTK_HIDPI_SUPPORT
return f;
}
class Fl_Win32_At_Exit {
public:
Fl_Win32_At_Exit() { }
@ -896,11 +930,14 @@ static int mouse_event(Fl_Window *window, int what, int button,
{
static int px, py, pmx, pmy;
POINT pt;
float scale = Fl_Graphics_Driver::default_driver().scale();
Fl::e_x = pt.x = (signed short)LOWORD(lParam);
Fl::e_y = pt.y = (signed short)HIWORD(lParam);
Fl::e_x /= scale;
Fl::e_y /= scale;
ClientToScreen(fl_xid(window), &pt);
Fl::e_x_root = pt.x;
Fl::e_y_root = pt.y;
Fl::e_x_root = pt.x / scale;
Fl::e_y_root = pt.y / scale;
#ifdef USE_CAPTURE_MOUSE_WIN
Fl_Window *mouse_window = window; // save "mouse window"
#endif
@ -1061,9 +1098,24 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar
//fl_msg.lPrivate = ???
Fl_Window *window = fl_find(hWnd);
float scale = Fl_Graphics_Driver::default_driver().scale();
if (window) switch (uMsg) {
#ifdef FLTK_HIDPI_SUPPORT
case 0x02E0: { // WM_DPICHANGED:
float f = HIWORD(wParam)/96.;
Fl::screen_driver()->scale(0, f);
Fl_Graphics_Driver::default_driver().scale(f);
//fprintf(LOG,"WM_DPICHANGED f=%.2f\n", f);fflush(LOG);
if (!window->parent()) {
window->hide();
window->show();
}
}
return 0;
#endif // FLTK_HIDPI_SUPPORT
case WM_QUIT: // this should not happen?
Fl::fatal("WM_QUIT message");
@ -1080,7 +1132,7 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar
break;
case WM_PAINT: {
Fl_Region R;
Fl_Region R, R2;
Fl_X *i = Fl_X::i(window);
window->driver()->wait_for_expose_value = 0;
char redraw_whole_window = false;
@ -1094,19 +1146,27 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar
R = CreateRectRgn(0,0,0,0);
int r = GetUpdateRgn(hWnd,R,0);
if (r==NULLREGION && !redraw_whole_window) {
Fl_Graphics_Driver::default_driver().XDestroyRegion(R);
DeleteObject(R);
break;
}
if (i->region) {
// convert i->region in FLTK units to R2 in drawing units
R2 = Fl_GDI_Graphics_Driver::scale_region(i->region, scale, false);
if (R2) {
// Also tell WIN32 that we are drawing someplace else as well...
CombineRgn(i->region, i->region, R, RGN_OR);
Fl_Graphics_Driver::default_driver().XDestroyRegion(R);
CombineRgn(R2, R2, R, RGN_OR);
DeleteObject(R);
} else {
i->region = R;
R2 = R;
}
if (window->type() == FL_DOUBLE_WINDOW) ValidateRgn(hWnd,0);
else ValidateRgn(hWnd,i->region);
else {
ValidateRgn(hWnd, R2);
}
// convert R2 in drawing units to i->region in FLTK units
i->region = Fl_GDI_Graphics_Driver::scale_region(R2, 1/scale, false, true);
window->clear_damage((uchar)(window->damage()|FL_DAMAGE_EXPOSE));
// These next two statements should not be here, so that all update
@ -1365,7 +1425,8 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar
} else {
Fl::handle(FL_SHOW, window);
resize_bug_fix = window;
window->size(LOWORD(lParam), HIWORD(lParam));
window->size(LOWORD(lParam)/scale, HIWORD(lParam)/scale);
//fprintf(LOG,"WM_SIZE parent size(%d,%d) s=%.2f\n",int(LOWORD(lParam)/scale),int(HIWORD(lParam)/scale),scale);
}
}
break;
@ -1376,7 +1437,8 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar
int ny = HIWORD(lParam);
if (nx & 0x8000) nx -= 65536;
if (ny & 0x8000) ny -= 65536;
window->position(nx, ny); }
//fprintf(LOG,"WM_MOVE position(%d,%d) s=%.2f\n",int(nx/scale),int(ny/scale),scale);
window->position(nx/scale, ny/scale); }
break;
case WM_SETCURSOR:
@ -1606,7 +1668,8 @@ void Fl_WinAPI_Window_Driver::resize(int X,int Y,int W,int H) {
// will cause continouly new redraw events.
if (W<=0) W = 1;
if (H<=0) H = 1;
SetWindowPos(fl_xid(pWindow), 0, X, Y, W, H, flags);
float s = Fl::screen_driver()->scale(0);
SetWindowPos(fl_xid(pWindow), 0, X*s, Y*s, W*s, H*s, flags);
}
}
@ -1716,10 +1779,11 @@ Fl_X* Fl_WinAPI_Window_Driver::makeWindow() {
DWORD style = WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
DWORD styleEx = WS_EX_LEFT;
int xp = w->x();
int yp = w->y();
int wp = w->w();
int hp = w->h();
float s = Fl::screen_driver()->scale(0);
int xp = w->x() * s;
int yp = w->y() * s;
int wp = w->w() * s;
int hp = w->h() * s;
int showit = 1;
@ -1779,7 +1843,7 @@ Fl_X* Fl_WinAPI_Window_Driver::makeWindow() {
} else {
if (!Fl::grab()) {
xp = xwm; yp = ywm;
x(xp); y(yp);
x(xp/s); y(yp/s);
}
xp -= bx;
yp -= by+bt;
@ -1892,15 +1956,16 @@ void Fl_WinAPI_Window_Driver::set_minmax(LPMINMAXINFO minmax)
hd *= 2;
hd += td;
minmax->ptMinTrackSize.x = minw() + wd;
minmax->ptMinTrackSize.y = minh() + hd;
float s = Fl::screen_driver()->scale(0);
minmax->ptMinTrackSize.x = s*minw() + wd;
minmax->ptMinTrackSize.y = s*minh() + hd;
if (maxw()) {
minmax->ptMaxTrackSize.x = maxw() + wd;
minmax->ptMaxSize.x = maxw() + wd;
minmax->ptMaxTrackSize.x = s*maxw() + wd;
minmax->ptMaxSize.x = s*maxw() + wd;
}
if (maxh()) {
minmax->ptMaxTrackSize.y = maxh() + hd;
minmax->ptMaxSize.y = maxh() + hd;
minmax->ptMaxTrackSize.y = s*maxh() + hd;
minmax->ptMaxSize.y = s*maxh() + hd;
}
}

View File

@ -3,7 +3,7 @@
//
// X specific code for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2016 by Bill Spitzak and others.
// Copyright 1998-2017 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
@ -719,14 +719,23 @@ void Fl_X11_Screen_Driver::close_display() {
XCloseDisplay(fl_display);
}
void Fl_X11_Screen_Driver::get_mouse(int &xx, int &yy) {
int Fl_X11_Screen_Driver::get_mouse_unscaled(int &mx, int &my) {
open_display();
Window root = RootWindow(fl_display, fl_screen);
Window c; int mx,my,cx,cy; unsigned int mask;
XQueryPointer(fl_display,root,&root,&c,&mx,&my,&cx,&cy,&mask);
xx = mx;
yy = my;
Window c; int cx,cy; unsigned int mask;
XQueryPointer(fl_display, root, &root, &c, &mx, &my, &cx, &cy, &mask);
#if USE_XFT
return screen_num_unscaled(mx, my);
#else
return screen_num(mx, my);
#endif
}
void Fl_X11_Screen_Driver::get_mouse(int &xx, int &yy) {
float s = scale(get_mouse_unscaled(xx, yy));
xx = xx/s;
yy = yy/s;
}
////////////////////////////////////////////////////////////////
@ -1079,14 +1088,18 @@ char fl_key_vector[32]; // used by Fl::get_key()
static int px, py;
static ulong ptime;
static void set_event_xy() {
static void set_event_xy(Fl_Window *win) {
# if CONSOLIDATE_MOTION
send_motion = 0;
# endif
Fl::e_x_root = fl_xevent->xbutton.x_root;
Fl::e_x = fl_xevent->xbutton.x;
Fl::e_y_root = fl_xevent->xbutton.y_root;
Fl::e_y = fl_xevent->xbutton.y;
float s = 1;
#if USE_XFT
s = Fl::screen_driver()->scale(win->driver()->screen_num());
#endif
Fl::e_x_root = fl_xevent->xbutton.x_root/s;
Fl::e_x = fl_xevent->xbutton.x/s;
Fl::e_y_root = fl_xevent->xbutton.y_root/s;
Fl::e_y = fl_xevent->xbutton.y/s;
Fl::e_state = fl_xevent->xbutton.state << 16;
fl_event_time = fl_xevent->xbutton.time;
# ifdef __sgi
@ -1203,12 +1216,6 @@ static KeySym fl_KeycodeToKeysym(Display *d, KeyCode k, unsigned i) {
return XKeycodeToKeysym(d, k, i);
}
static void fl_init_workarea()
{
Fl_X11_Screen_Driver *drv = (Fl_X11_Screen_Driver*)Fl::screen_driver();
drv->init_workarea();
}
int fl_handle(const XEvent& thisevent)
{
XEvent xevent = thisevent;
@ -1241,13 +1248,17 @@ int fl_handle(const XEvent& thisevent)
if( XRRUpdateConfiguration_f && xevent.type == randrEventBase + RRScreenChangeNotify) {
XRRUpdateConfiguration_f(&xevent);
Fl::call_screen_init();
fl_init_workarea();
#if USE_XFT
float factor = Fl::screen_driver()->default_scale_factor();
for (int screen = 0; screen <= Fl::screen_count(); screen++)
Fl::screen_driver()->rescale_all_windows_from_screen(screen, factor);
#endif // USE_XFT
Fl::handle(FL_SCREEN_CONFIGURATION_CHANGED, NULL);
}
#endif
#endif // USE_XRANDR
if (xevent.type == PropertyNotify && xevent.xproperty.atom == fl_NET_WORKAREA) {
fl_init_workarea();
Fl::screen_driver()->init_workarea();
}
switch (xevent.type) {
@ -1647,8 +1658,17 @@ fprintf(stderr,"\n");*/
# endif
case GraphicsExpose:
window->damage(FL_DAMAGE_EXPOSE, xevent.xexpose.x, xevent.xexpose.y,
xevent.xexpose.width, xevent.xexpose.height);
{
#if USE_XFT
int ns = window->driver()->screen_num();
float s = Fl::screen_driver()->scale(ns);
window->damage(FL_DAMAGE_EXPOSE, xevent.xexpose.x/s, xevent.xexpose.y/s,
xevent.xexpose.width/s + 2, xevent.xexpose.height/s + 2);
#else
window->damage(FL_DAMAGE_EXPOSE, xevent.xexpose.x, xevent.xexpose.y,
xevent.xexpose.width, xevent.xexpose.height);
#endif
}
return 1;
case FocusIn:
@ -1867,13 +1887,13 @@ fprintf(stderr,"\n");*/
// replace XK_ISO_Left_Tab (Shift-TAB) with FL_Tab (modifier flags are set correctly by X11)
if (Fl::e_keysym == 0xfe20) Fl::e_keysym = FL_Tab;
set_event_xy();
set_event_xy(window);
Fl::e_is_click = 0; }
break;
case ButtonPress:
Fl::e_keysym = FL_Button + xevent.xbutton.button;
set_event_xy();
set_event_xy(window);
Fl::e_dx = Fl::e_dy = 0;
if (xevent.xbutton.button == Button4) {
Fl::e_dy = -1; // Up
@ -1924,7 +1944,7 @@ fprintf(stderr,"\n");*/
break;
case MotionNotify:
set_event_xy();
set_event_xy(window);
# if CONSOLIDATE_MOTION
send_motion = fl_xmousewin = window;
in_a_window = true;
@ -1938,7 +1958,7 @@ fprintf(stderr,"\n");*/
case ButtonRelease:
Fl::e_keysym = FL_Button + xevent.xbutton.button;
set_event_xy();
set_event_xy(window);
Fl::e_state &= ~(FL_BUTTON1 << (xevent.xbutton.button-1));
if (xevent.xbutton.button == Button4 ||
xevent.xbutton.button == Button5) return 0;
@ -1951,7 +1971,7 @@ fprintf(stderr,"\n");*/
case EnterNotify:
if (xevent.xcrossing.detail == NotifyInferior) break;
// XInstallColormap(fl_display, Fl_X::i(window)->colormap);
set_event_xy();
set_event_xy(window);
Fl::e_state = xevent.xcrossing.state << 16;
event = FL_ENTER;
@ -1967,7 +1987,7 @@ fprintf(stderr,"\n");*/
case LeaveNotify:
if (xevent.xcrossing.detail == NotifyInferior) break;
set_event_xy();
set_event_xy(window);
Fl::e_state = xevent.xcrossing.state << 16;
fl_xmousewin = 0;
in_a_window = false; // make do_queued_events produce FL_LEAVE event
@ -1992,10 +2012,39 @@ fprintf(stderr,"\n");*/
Window cr; int X, Y, W = actual.width, H = actual.height;
XTranslateCoordinates(fl_display, fl_xid(window), actual.root,
0, 0, &X, &Y, &cr);
#if USE_XFT // detect when window changes screen
int num = 0;
Fl_X11_Screen_Driver *d = (Fl_X11_Screen_Driver*)Fl::screen_driver();
num = d->screen_num_unscaled(X, Y, actual.width, actual.height);
Fl_X11_Window_Driver *wd = Fl_X11_Window_Driver::driver(window);
int olds = wd->screen_num();
float s = d->scale(num);
if (num != olds) {
if (s != d->scale(olds) &&
!Fl_X11_Window_Driver::data_for_resize_window_between_screens_.busy &&
window->user_data() != &Fl_X11_Screen_Driver::transient_scale_display) {
Fl_X11_Window_Driver::data_for_resize_window_between_screens_.busy = true;
Fl_X11_Window_Driver::data_for_resize_window_between_screens_.screen = num;
// resize_after_screen_change() works also if called here, but calling it
// a second later gives a more pleasant user experience when moving windows between distinct screens
Fl::add_timeout(1, Fl_X11_Window_Driver::resize_after_screen_change, window);
}
wd->screen_num(num);
}
#endif // USE_XFT
// tell Fl_Window about it and set flag to prevent echoing:
resize_bug_fix = window;
#if USE_XFT
if (!Fl_X11_Window_Driver::data_for_resize_window_between_screens_.busy &&
( W != int(window->w()*s) || H != int(window->h()*s) ) ) {
window->resize(X/s, Y/s, W/s, H/s);
} else {
window->position(X/s, Y/s);
}
#else
window->resize(X, Y, W, H);
#endif
break; // allow add_handler to do something too
}
@ -2017,7 +2066,13 @@ fprintf(stderr,"\n");*/
// tell Fl_Window about it and set flag to prevent echoing:
if ( !wasXExceptionRaised() ) {
resize_bug_fix = window;
window->position(xpos, ypos);
#if USE_XFT
int ns = window->driver()->screen_num();
float s = Fl::screen_driver()->scale(ns);
#else
float s = 1;
#endif
window->position(xpos/s, ypos/s);
}
break;
}
@ -2066,15 +2121,16 @@ void Fl_X11_Window_Driver::resize(int X,int Y,int W,int H) {
}
if (resize_from_program && shown()) {
float s = Fl::screen_driver()->scale(screen_num());
if (is_a_resize) {
if (!pWindow->resizable()) pWindow->size_range(w(), h(), w(), h());
if (is_a_move) {
XMoveResizeWindow(fl_display, fl_xid(pWindow), X, Y, W>0 ? W : 1, H>0 ? H : 1);
XMoveResizeWindow(fl_display, fl_xid(pWindow), X*s, Y*s, W>0 ? W*s : 1, H>0 ? H*s : 1);
} else {
XResizeWindow(fl_display, fl_xid(pWindow), W>0 ? W : 1, H>0 ? H : 1);
XResizeWindow(fl_display, fl_xid(pWindow), W>0 ? W*s : 1, H>0 ? H*s : 1);
}
} else
XMoveWindow(fl_display, fl_xid(pWindow), X, Y);
XMoveWindow(fl_display, fl_xid(pWindow), X*s, Y*s);
}
}
@ -2179,7 +2235,7 @@ void Fl_X11_Window_Driver::fullscreen_on() {
right = fullscreen_screen_right();
if ((top < 0) || (bottom < 0) || (left < 0) || (right < 0)) {
top = Fl::screen_num(x(), y(), w(), h());
top = screen_num();
bottom = top;
left = top;
right = top;
@ -2361,11 +2417,31 @@ void Fl_X::make_xid(Fl_Window* win, XVisualInfo *visual, Colormap colormap)
fl_background_pixel = -1;
mask |= CWBackPixel;
}
// reproduce the window cursor if a window is hidden and then recreated (e.g., rescaled)
attr.cursor = Fl_X11_Window_Driver::driver(win)->current_cursor_;
mask |= CWCursor;
float s = 1;
#if USE_XFT
//compute adequate screen where to put the window
int nscreen = 0;
if (win->parent()) {
nscreen = win->top_window()->driver()->screen_num();
} else if (win->force_position() && Fl_X11_Window_Driver::driver(win)->screen_num_ >= 0) {
nscreen = win->driver()->screen_num();
} else {
Fl_Window *hint = Fl::first_window();
if (hint) {
nscreen = hint->top_window()->driver()->screen_num();
}
}
Fl_X11_Window_Driver::driver(win)->screen_num(nscreen);
s = Fl::screen_driver()->scale(nscreen);
//if (!win->parent()) printf("win creation on screen #%d\n", nscreen);
#endif
Fl_X* xp =
set_xid(win, XCreateWindow(fl_display,
root,
X, Y, W, H,
X*s, Y*s, W*s, H*s,
0, // borderwidth
visual->depth,
InputOutput,
@ -2525,12 +2601,20 @@ void Fl_X11_Window_Driver::sendxjunk() {
XSizeHints *hints = XAllocSizeHints();
// memset(&hints, 0, sizeof(hints)); jreiser suggestion to fix purify?
hints->min_width = minw();
hints->min_height = minh();
hints->max_width = maxw();
hints->max_height = maxh();
hints->width_inc = dw();
hints->height_inc = dh();
float s = Fl::screen_driver()->scale(screen_num());
hints->min_width = s*minw();
hints->min_height = s*minh();
hints->max_width = s*maxw();
hints->max_height = s*maxh();
if (int(s) == s) { // use win size increment value only if scale is an integer. Is it possible to do better?
hints->width_inc = s*dw();
hints->height_inc = s*dh();
} else {
hints->width_inc = 0;
hints->height_inc = 0;
}
hints->win_gravity = StaticGravity;
// see the file /usr/include/X11/Xm/MwmUtil.h:
@ -2547,8 +2631,8 @@ void Fl_X11_Window_Driver::sendxjunk() {
// unfortunately we can't set just one maximum size. Guess a
// value for the other one. Some window managers will make the
// window fit on screen when maximized, others will put it off screen:
if (hints->max_width < hints->min_width) hints->max_width = Fl::w();
if (hints->max_height < hints->min_height) hints->max_height = Fl::h();
if (hints->max_width < hints->min_width) hints->max_width = Fl::w()*s;
if (hints->max_height < hints->min_height) hints->max_height = Fl::h()*s;
}
if (hints->width_inc && hints->height_inc) hints->flags |= PResizeInc;
if (aspect()) {
@ -2566,8 +2650,8 @@ void Fl_X11_Window_Driver::sendxjunk() {
if (force_position()) {
hints->flags |= USPosition;
hints->x = w->x();
hints->y = w->y();
hints->x = s*w->x();
hints->y = s*w->y();
}
if (!w->border()) {
@ -2730,6 +2814,7 @@ int Fl_X11_Window_Driver::set_cursor(Fl_Cursor c) {
#undef cache_cursor
XDefineCursor(fl_display, fl_xid(pWindow), xc);
current_cursor_ = xc;
return 1;
}
@ -2895,6 +2980,7 @@ void printFront(Fl_Widget *o, void *data)
//printer.print_window_part( win, 0,0, win->w(), win->h(), - win->w()/2, - win->h()/2 );
#else
printer.print_window(win);
//printer.print_window_part( win, 0,0, win->w(), win->h(), 0,0 );
#endif
printer.end_page();
@ -2909,8 +2995,9 @@ void copyFront(Fl_Widget *o, void *data)
Fl_Window *win = Fl::first_window();
if (!win) return;
Fl_Copy_Surface *surf = new Fl_Copy_Surface(win->decorated_w(), win->decorated_h());
surf->set_current();
Fl_Surface_Device::push_current(surf);
surf->draw_decorated_window(win); // draw the window content
Fl_Surface_Device::pop_current();
delete surf; // put the window on the clipboard
o->window()->show();
}

View File

@ -34,7 +34,7 @@
*
This class is implemented only on the MSWindows platform.
*/
class FL_EXPORT Fl_GDI_Graphics_Driver : public Fl_Graphics_Driver {
class FL_EXPORT Fl_GDI_Graphics_Driver : public Fl_Scalable_Graphics_Driver {
private:
BOOL alpha_blend_(int x, int y, int w, int h, HDC src_gc, int srcx, int srcy, int srcw, int srch);
int depth; // to support translation
@ -59,55 +59,58 @@ public:
// --- bitmap stuff
Fl_Bitmask create_bitmask(int w, int h, const uchar *array);
void delete_bitmask(Fl_Bitmask bm);
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);
virtual void draw_unscaled(const char* str, int n, int x, int y);
virtual void draw_unscaled(int angle, const char *str, int n, int x, int y);
virtual void rtl_draw_unscaled(const char* str, int n, int x, int y);
virtual void font_unscaled(Fl_Font face, Fl_Fontsize size);
void draw_unscaled(Fl_Pixmap *pxm, float s, int XP, int YP, int WP, int HP, int cx, int cy);
void draw_unscaled(Fl_Bitmap *pxm, float s, int XP, int YP, int WP, int HP, int cx, int cy);
void draw_unscaled(Fl_RGB_Image *img, float s, int XP, int YP, int WP, int HP, int cx, int cy);
int draw_scaled(Fl_Image *img, int XP, int YP, int WP, int HP);
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);
virtual void draw_image_unscaled(const uchar* buf, int X,int Y,int W,int H, int D=3, int L=0);
virtual void draw_image_unscaled(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=3);
virtual void draw_image_mono_unscaled(const uchar* buf, int X,int Y,int W,int H, int D=1, int L=0);
virtual void draw_image_mono_unscaled(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=1);
fl_uintptr_t cache(Fl_Pixmap *img, int w, int h, const char *const*array);
fl_uintptr_t cache(Fl_Bitmap *img, int w, int h, const uchar *array);
void uncache(Fl_RGB_Image *img, fl_uintptr_t &id_, fl_uintptr_t &mask_);
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();
virtual double width_unscaled(const char *str, int n);
virtual double width_unscaled(unsigned int c);
void text_extents_unscaled(const char*, int n, int& dx, int& dy, int& w, int& h);
int height_unscaled();
int descent_unscaled();
Fl_Fontsize size_unscaled();
#if ! defined(FL_DOXYGEN)
void copy_offscreen_with_alpha(int x,int y,int w,int h,HBITMAP bitmap,int srcx,int srcy);
#endif
void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy);
virtual void copy_offscreen_unscaled(float x, float y, float w, float h, Fl_Offscreen pixmap, float srcx, float srcy);
void add_rectangle_to_region(Fl_Region r, int x, int y, int w, int h);
Fl_Region XRectangleRegion(int x, int y, int w, int h);
void XDestroyRegion(Fl_Region r);
void translate_all(int x, int y);
void untranslate_all(void);
static HRGN scale_region(HRGN r, float f, bool keep, bool inflate=false);
virtual void scale(float f);
protected:
void transformed_vertex0(int x, int y);
void transformed_vertex0(float x, float y);
void fixloop();
// --- implementation is in src/fl_rect.cxx which includes src/cfg_gfx/gdi_rect.cxx
void point(int x, int y);
void rect(int x, int y, int w, int h);
virtual void point_unscaled(float x, float y);
void rect_unscaled(float x, float y, float w, float h);
void focus_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);
void rectf_unscaled(float x, float y, float w, float h);
virtual void line_unscaled(float x, float y, float x1, float y1);
virtual void line_unscaled(float x, float y, float x1, float y1, float x2, float y2);
virtual void xyline_unscaled(float x, float y, float x1);
virtual void xyline_unscaled(float x, float y, float x1, float y2);
virtual void xyline_unscaled(float x, float y, float x1, float y2, float x3);
virtual void yxline_unscaled(float x, float y, float y1);
virtual void yxline_unscaled(float x, float y, float y1, float x2);
virtual void yxline_unscaled(float x, float y, float y1, float x2, float y3);
virtual void loop_unscaled(float x0, float y0, float x1, float y1, float x2, float y2);
virtual void loop_unscaled(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3);
virtual void polygon_unscaled(float x0, float y0, float x1, float y1, float x2, float y2);
virtual void polygon_unscaled(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float 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);
@ -115,24 +118,23 @@ protected:
void push_no_clip();
void pop_clip();
void restore_clip();
virtual Fl_Region scale_clip(float f);
// --- 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);
virtual void ellipse_unscaled(double xt, double yt, double rx, double ry);
// --- 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);
virtual void arc_unscaled(float x, float y, float w, float h, double a1, double a2);
virtual void pie_unscaled(float x, float y, float w, float 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);
virtual void line_style_unscaled(int style, float width, char* dashes);
// --- 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_; }
@ -162,8 +164,8 @@ private:
transparent_f_type TransparentBlt();
public:
virtual int has_feature(driver_feature mask) { return mask & (NATIVE | PRINTER); }
void draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy);
void draw(Fl_Bitmap *bm, int XP, int YP, int WP, int HP, int cx, int cy);
void draw_unscaled(Fl_Pixmap *pxm, float s, int XP, int YP, int WP, int HP, int cx, int cy);
void draw_unscaled(Fl_Bitmap *bm, float s, int XP, int YP, int WP, int HP, int cx, int cy);
int draw_scaled(Fl_Image *img, int XP, int YP, int WP, int HP);
};

View File

@ -104,7 +104,7 @@ HDC fl_makeDC(HBITMAP bitmap) {
return new_gc;
}
void Fl_GDI_Graphics_Driver::copy_offscreen(int x,int y,int w,int h,HBITMAP bitmap,int srcx,int srcy) {
void Fl_GDI_Graphics_Driver::copy_offscreen_unscaled(float x, float y, float w, float h, Fl_Offscreen bitmap, float srcx, float srcy) {
HDC new_gc = CreateCompatibleDC(gc_);
int save = SaveDC(new_gc);
SelectObject(new_gc, bitmap);
@ -162,7 +162,7 @@ void Fl_GDI_Graphics_Driver::add_rectangle_to_region(Fl_Region r, int X, int Y,
XDestroyRegion(R);
}
void Fl_GDI_Graphics_Driver::transformed_vertex0(int x, int y) {
void Fl_GDI_Graphics_Driver::transformed_vertex0(float x, float y) {
if (!n || x != p[n-1].x || y != p[n-1].y) {
if (n >= p_size) {
p_size = p ? 2*p_size : 16;
@ -228,6 +228,45 @@ void Fl_GDI_Graphics_Driver::set_spot(int font, int size, int X, int Y, int W, i
}
void Fl_GDI_Graphics_Driver::scale(float f) {
if (f != scale_) {
size_ = 0;
scale_ = f;
//line_style(FL_SOLID); // scale also default line width
}
}
/* Rescale region r with factor f and returns the scaled region.
The input region is deleted if keep is false.
The input region is inflated by 1 unit before rescaling if inflate is true.
Region r is returned unchanged if r is null or f is 1.
*/
HRGN Fl_GDI_Graphics_Driver::scale_region(HRGN r, float f, bool keep, bool inflate) {
if (r && f != 1) {
DWORD size = GetRegionData(r, 0, NULL);
RGNDATA *pdata = (RGNDATA*)malloc(size);
GetRegionData(r, size, pdata);
if (!keep) DeleteObject(r);
if (inflate) {
RECT *rects = (RECT*)&(pdata->Buffer);
for (DWORD i = 0; i < pdata->rdh.nCount; i++) {
InflateRect(rects+i, 1, 1);
}
}
XFORM xform = {f, 0, 0, f, 0, 0};
r = ExtCreateRegion(&xform, size, pdata);
free(pdata);
}
return r;
}
Fl_Region Fl_GDI_Graphics_Driver::scale_clip(float f) {
HRGN r = rstack[rstackptr];
HRGN r2 = scale_region(r, f, true);
return (r == r2 ? NULL : (rstack[rstackptr] = r2, r));
}
//
// End of "$Id$".

View File

@ -35,7 +35,7 @@
#include <FL/math.h>
#include <FL/x.H>
void Fl_GDI_Graphics_Driver::arc(int x,int y,int w,int h,double a1,double a2) {
void Fl_GDI_Graphics_Driver::arc_unscaled(float x, float y, float w, float h, double a1, double a2) {
if (w <= 0 || h <= 0) return;
int xa = x+w/2+int(w*cos(a1/180.0*M_PI));
int ya = y+h/2-int(h*sin(a1/180.0*M_PI));
@ -47,7 +47,7 @@ void Fl_GDI_Graphics_Driver::arc(int x,int y,int w,int h,double a1,double a2) {
} else Arc(gc_, x, y, x+w, y+h, xa, ya, xb, yb);
}
void Fl_GDI_Graphics_Driver::pie(int x,int y,int w,int h,double a1,double a2) {
void Fl_GDI_Graphics_Driver::pie_unscaled(float x, float y, float w, float h, double a1, double a2) {
if (w <= 0 || h <= 0) return;
if (a1 == a2) return;
int xa = x+w/2+int(w*cos(a1/180.0*M_PI));

View File

@ -323,34 +323,40 @@ static void fl_font(Fl_Graphics_Driver *driver, Fl_Font fnum, Fl_Fontsize size,
driver->Fl_Graphics_Driver::font(0, 0);
return;
}
if (fnum == driver->Fl_Graphics_Driver::font() && size == driver->size() && angle == fl_angle_) return;
if (fnum == driver->Fl_Graphics_Driver::font() && size == ((Fl_GDI_Graphics_Driver*)driver)->size_unscaled() && angle == fl_angle_) return;
fl_angle_ = angle;
driver->Fl_Graphics_Driver::font(fnum, size);
driver->font_descriptor( find(fnum, size, angle) );
}
void Fl_GDI_Graphics_Driver::font(Fl_Font fnum, Fl_Fontsize size) {
void Fl_GDI_Graphics_Driver::font_unscaled(Fl_Font fnum, Fl_Fontsize size) {
fl_font(this, fnum, size, 0);
}
int Fl_GDI_Graphics_Driver::height() {
int Fl_GDI_Graphics_Driver::height_unscaled() {
Fl_Font_Descriptor *fl_fontsize = font_descriptor();
if (fl_fontsize) return (fl_fontsize->metr.tmAscent + fl_fontsize->metr.tmDescent);
else return -1;
}
int Fl_GDI_Graphics_Driver::descent() {
int Fl_GDI_Graphics_Driver::descent_unscaled() {
Fl_Font_Descriptor *fl_fontsize = font_descriptor();
if (fl_fontsize) return fl_fontsize->metr.tmDescent;
else return -1;
}
Fl_Fontsize Fl_GDI_Graphics_Driver::size_unscaled() {
if (font_descriptor()) return size_;
return -1;
}
// Unicode string buffer
static unsigned short *wstr = NULL;
static int wstr_len = 0;
double Fl_GDI_Graphics_Driver::width(const char* c, int n) {
double Fl_GDI_Graphics_Driver::width_unscaled(const char* c, int n) {
int i = 0;
if (!font_descriptor()) return -1.0;
double w = 0.0;
@ -362,13 +368,13 @@ double Fl_GDI_Graphics_Driver::width(const char* c, int n) {
// if (l < 1) l = 1;
i += l;
if (!fl_nonspacing(ucs)) {
w += width(ucs);
w += width_unscaled(ucs);
}
}
return w;
}
double Fl_GDI_Graphics_Driver::width(unsigned int c) {
double Fl_GDI_Graphics_Driver::width_unscaled(unsigned int c) {
Fl_Font_Descriptor *fl_fontsize = font_descriptor();
unsigned int r;
SIZE s;
@ -466,7 +472,7 @@ static void on_printer_extents_update(int &dx, int &dy, int &w, int &h, HDC gc)
}
// Function to determine the extent of the "inked" area of the glyphs in a string
void Fl_GDI_Graphics_Driver::text_extents(const char *c, int n, int &dx, int &dy, int &w, int &h) {
void Fl_GDI_Graphics_Driver::text_extents_unscaled(const char *c, int n, int &dx, int &dy, int &w, int &h) {
Fl_Font_Descriptor *fl_fontsize = font_descriptor();
if (!fl_fontsize) { // no valid font, nothing to measure
@ -571,14 +577,14 @@ void Fl_GDI_Graphics_Driver::text_extents(const char *c, int n, int &dx, int &dy
exit_error:
// some error here - just return fl_measure values
w = (int)width(c, n);
h = height();
h = height_unscaled();
dx = 0;
dy = descent() - h;
dy = descent_unscaled() - h;
EXTENTS_UPDATE(dx, dy, w, h, gc_);
return;
} // fl_text_extents
void Fl_GDI_Graphics_Driver::draw(const char* str, int n, int x, int y) {
void Fl_GDI_Graphics_Driver::draw_unscaled(const char* str, int n, int x, int y) {
COLORREF oldColor = SetTextColor(gc_, fl_RGB());
// avoid crash if no font has been set yet
if (!font_descriptor()) this->font(FL_HELVETICA, FL_NORMAL_SIZE);
@ -593,8 +599,8 @@ void Fl_GDI_Graphics_Driver::draw(const char* str, int n, int x, int y) {
SetTextColor(gc_, oldColor); // restore initial state
}
void Fl_GDI_Graphics_Driver::draw(int angle, const char* str, int n, int x, int y) {
fl_font(this, Fl_Graphics_Driver::font(), size(), angle);
void Fl_GDI_Graphics_Driver::draw_unscaled(int angle, const char* str, int n, int x, int y) {
fl_font(this, Fl_Graphics_Driver::font(), size_unscaled(), angle);
int wn = 0; // count of UTF16 cells to render full string
COLORREF oldColor = SetTextColor(gc_, fl_RGB());
SelectObject(gc_, font_descriptor()->fid);
@ -606,10 +612,10 @@ void Fl_GDI_Graphics_Driver::draw(int angle, const char* str, int n, int x, int
}
TextOutW(gc_, x, y, (WCHAR*)wstr, wn);
SetTextColor(gc_, oldColor);
fl_font(this, Fl_Graphics_Driver::font(), size(), 0);
fl_font(this, Fl_Graphics_Driver::font(), size_unscaled(), 0);
}
void Fl_GDI_Graphics_Driver::rtl_draw(const char* c, int n, int x, int y) {
void Fl_GDI_Graphics_Driver::rtl_draw_unscaled(const char* c, int n, int x, int y) {
int wn;
wn = fl_utf8toUtf16(c, n, wstr, wstr_len);
if(wn >= wstr_len) {
@ -634,7 +640,7 @@ void Fl_GDI_Graphics_Driver::rtl_draw(const char* c, int n, int x, int y) {
}
#else
UINT old_align = SetTextAlign(gc_, TA_RIGHT | TA_RTLREADING);
TextOutW(gc_, x, y - height() + descent(), (WCHAR*)wstr, wn);
TextOutW(gc_, x, y - height_unscaled() + descent_unscaled(), (WCHAR*)wstr, wn);
SetTextAlign(gc_, old_align);
#endif
SetTextColor(gc_, oldColor);

View File

@ -42,6 +42,7 @@
#include <FL/Fl_Printer.H>
#include <FL/fl_draw.H>
#include <FL/x.H>
#include <FL/Fl_Image_Surface.H>
#define MAXBUFFER 0x40000 // 256k
@ -284,7 +285,7 @@ static void innards(const uchar *buf, int X, int Y, int W, int H,
}
}
void Fl_GDI_Graphics_Driver::draw_image(const uchar* buf, int x, int y, int w, int h, int d, int l){
void Fl_GDI_Graphics_Driver::draw_image_unscaled(const uchar* buf, int x, int y, int w, int h, int d, int l){
if (fl_abs(d)&FL_IMAGE_WITH_ALPHA) {
d ^= FL_IMAGE_WITH_ALPHA;
innards(buf,x,y,w,h,d,l,fl_abs(d),0,0, gc_);
@ -293,7 +294,7 @@ void Fl_GDI_Graphics_Driver::draw_image(const uchar* buf, int x, int y, int w, i
}
}
void Fl_GDI_Graphics_Driver::draw_image(Fl_Draw_Image_Cb cb, void* data,
void Fl_GDI_Graphics_Driver::draw_image_unscaled(Fl_Draw_Image_Cb cb, void* data,
int x, int y, int w, int h,int d) {
if (fl_abs(d)&FL_IMAGE_WITH_ALPHA) {
d ^= FL_IMAGE_WITH_ALPHA;
@ -303,7 +304,7 @@ void Fl_GDI_Graphics_Driver::draw_image(Fl_Draw_Image_Cb cb, void* data,
}
}
void Fl_GDI_Graphics_Driver::draw_image_mono(const uchar* buf, int x, int y, int w, int h, int d, int l){
void Fl_GDI_Graphics_Driver::draw_image_mono_unscaled(const uchar* buf, int x, int y, int w, int h, int d, int l){
if (fl_abs(d)&FL_IMAGE_WITH_ALPHA) {
d ^= FL_IMAGE_WITH_ALPHA;
innards(buf,x,y,w,h,d,l,1,0,0, gc_);
@ -312,7 +313,7 @@ void Fl_GDI_Graphics_Driver::draw_image_mono(const uchar* buf, int x, int y, int
}
}
void Fl_GDI_Graphics_Driver::draw_image_mono(Fl_Draw_Image_Cb cb, void* data,
void Fl_GDI_Graphics_Driver::draw_image_mono_unscaled(Fl_Draw_Image_Cb cb, void* data,
int x, int y, int w, int h,int d) {
if (fl_abs(d)&FL_IMAGE_WITH_ALPHA) {
d ^= FL_IMAGE_WITH_ALPHA;
@ -399,11 +400,15 @@ void Fl_GDI_Graphics_Driver::delete_bitmask(Fl_Bitmask bm) {
DeleteObject((HGDIOBJ)bm);
}
void Fl_GDI_Graphics_Driver::draw(Fl_Bitmap *bm, int XP, int YP, int WP, int HP, int cx, int cy) {
void Fl_GDI_Graphics_Driver::draw_unscaled(Fl_Bitmap *bm, float s, int XP, int YP, int WP, int HP, int cx, int cy) {
int X, Y, W, H;
if (Fl_Graphics_Driver::prepare(bm, XP, YP, WP, HP, cx, cy, X, Y, W, H)) {
return;
}
X = X*s;
Y = Y*s;
cache_size(bm, W, H);
cx *= s; cy *= s;
HDC tempdc = CreateCompatibleDC(gc_);
int save = SaveDC(tempdc);
@ -423,7 +428,7 @@ Fl_GDI_Printer_Graphics_Driver::transparent_f_type Fl_GDI_Printer_Graphics_Drive
return fpter;
}
void Fl_GDI_Printer_Graphics_Driver::draw(Fl_Bitmap *bm, int XP, int YP, int WP, int HP, int cx, int cy) {
void Fl_GDI_Printer_Graphics_Driver::draw_unscaled(Fl_Bitmap *bm, float s, int XP, int YP, int WP, int HP, int cx, int cy) {
int X, Y, W, H;
transparent_f_type fl_TransparentBlt = TransparentBlt();
if (!fl_TransparentBlt) {
@ -467,34 +472,33 @@ void Fl_GDI_Printer_Graphics_Driver::draw(Fl_Bitmap *bm, int XP, int YP, int WP,
static Fl_Offscreen build_id(Fl_RGB_Image *img, void **pmask)
{
Fl_Offscreen offs = fl_create_offscreen(img->w(), img->h());
Fl_Image_Surface *surface = new Fl_Image_Surface(img->w(), img->h());
Fl_Surface_Device::push_current(surface);
if ((img->d() == 2 || img->d() == 4) && fl_can_do_alpha_blending()) {
fl_begin_offscreen(offs);
fl_draw_image(img->array, 0, 0, img->w(), img->h(), img->d()|FL_IMAGE_WITH_ALPHA, img->ld());
fl_end_offscreen();
} else {
fl_begin_offscreen(offs);
fl_draw_image(img->array, 0, 0, img->w(), img->h(), img->d(), img->ld());
fl_end_offscreen();
if (img->d() == 2 || img->d() == 4) {
*pmask = fl_create_alphamask(img->w(), img->h(), img->d(), img->ld(), img->array);
}
}
Fl_Surface_Device::pop_current();
Fl_Offscreen offs = surface->get_offscreen_before_delete();
delete surface;
return offs;
}
void Fl_GDI_Graphics_Driver::draw(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy) {
int X, Y, W, H;
// Don't draw an empty image...
if (!img->d() || !img->array) {
Fl_Graphics_Driver::draw_empty(img, XP, YP);
return;
void Fl_GDI_Graphics_Driver::draw_unscaled(Fl_RGB_Image *img, float s, int X, int Y, int W, int H, int cx, int cy) {
X = X*s;
Y = Y*s;
cache_size(img, W, H);
cx *= s; cy *= s;
if (!*Fl_Graphics_Driver::id(img)) {
*Fl_Graphics_Driver::id(img) = (fl_uintptr_t)build_id(img, (void**)(Fl_Graphics_Driver::mask(img)));
*cache_scale(img) = 1;
}
if (start_image(img, XP, YP, WP, HP, cx, cy, X, Y, W, H)) {
return;
}
if (!*Fl_Graphics_Driver::id(img)) *Fl_Graphics_Driver::id(img) = (fl_uintptr_t)build_id(img, (void**)(Fl_Graphics_Driver::mask(img)));
Fl_Region r2 = scale_clip(s);
if (*Fl_Graphics_Driver::mask(img)) {
HDC new_gc = CreateCompatibleDC(gc_);
int save = SaveDC(new_gc);
@ -509,6 +513,7 @@ void Fl_GDI_Graphics_Driver::draw(Fl_RGB_Image *img, int XP, int YP, int WP, int
} else {
copy_offscreen(X, Y, W, H, (Fl_Offscreen)*Fl_Graphics_Driver::id(img), cx, cy);
}
unscale_clip(r2);
}
int Fl_GDI_Printer_Graphics_Driver::draw_scaled(Fl_Image *img, int XP, int YP, int WP, int HP) {
@ -525,21 +530,26 @@ int Fl_GDI_Printer_Graphics_Driver::draw_scaled(Fl_Image *img, int XP, int YP, i
return 1;
}
int Fl_GDI_Graphics_Driver::draw_scaled(Fl_Image *img, int XP, int YP, int WP, int HP) {
Fl_RGB_Image *rgb = img->as_rgb_image();
if (!rgb || !rgb->array) return 0; // for bitmaps and pixmaps
if ((rgb->d() % 2) == 0 && !can_do_alpha_blending()) return 0;
if (!*Fl_Graphics_Driver::id(rgb)) *Fl_Graphics_Driver::id(rgb) = (fl_uintptr_t)build_id(rgb,
if (!*Fl_Graphics_Driver::id(rgb)) {
*Fl_Graphics_Driver::id(rgb) = (fl_uintptr_t)build_id(rgb,
(void**)(Fl_Graphics_Driver::mask(rgb)));
*cache_scale(rgb) = 1;
}
cache_size(img, WP, HP);
HDC new_gc = CreateCompatibleDC(gc_);
int save = SaveDC(new_gc);
SelectObject(new_gc, (HBITMAP)*Fl_Graphics_Driver::id(rgb));
if ( (rgb->d() % 2) == 0 ) {
alpha_blend_(XP, YP, WP, HP, new_gc, 0, 0, rgb->w(), rgb->h());
alpha_blend_(XP*scale_, YP*scale_, WP, HP, new_gc, 0, 0, rgb->w(), rgb->h());
} else {
SetStretchBltMode(gc_, HALFTONE);
StretchBlt(gc_, XP, YP, WP, HP, new_gc, 0, 0, rgb->w(), rgb->h(), SRCCOPY);
StretchBlt(gc_, XP*scale_, YP*scale_, WP, HP, new_gc, 0, 0, rgb->w(), rgb->h(), SRCCOPY);
}
RestoreDC(new_gc, save);
DeleteDC(new_gc);
@ -587,13 +597,17 @@ static Fl_Bitmask fl_create_bitmap(int w, int h, const uchar *data) {
return bm;
}
fl_uintptr_t Fl_GDI_Graphics_Driver::cache(Fl_Bitmap*, int w, int h, const uchar *array) {
fl_uintptr_t Fl_GDI_Graphics_Driver::cache(Fl_Bitmap *bm, int w, int h, const uchar *array) {
*cache_scale(bm) = Fl_Scalable_Graphics_Driver::scale();
return (fl_uintptr_t)fl_create_bitmap(w, h, array);
}
void Fl_GDI_Graphics_Driver::draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) {
int X, Y, W, H;
if (Fl_Graphics_Driver::prepare(pxm, XP, YP, WP, HP, cx, cy, X, Y, W, H)) return;
void Fl_GDI_Graphics_Driver::draw_unscaled(Fl_Pixmap *pxm, float s, int X, int Y, int W, int H, int cx, int cy) {
X = X*s;
Y = Y*s;
cache_size(pxm, W, H);
cx *= s; cy *= s;
Fl_Region r2 = scale_clip(s);
if (*Fl_Graphics_Driver::mask(pxm)) {
HDC new_gc = CreateCompatibleDC(gc_);
int save = SaveDC(new_gc);
@ -606,10 +620,11 @@ void Fl_GDI_Graphics_Driver::draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP
} else {
copy_offscreen(X, Y, W, H, (Fl_Offscreen)*Fl_Graphics_Driver::id(pxm), cx, cy);
}
unscale_clip(r2);
}
void Fl_GDI_Printer_Graphics_Driver::draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) {
void Fl_GDI_Printer_Graphics_Driver::draw_unscaled(Fl_Pixmap *pxm, float s, int XP, int YP, int WP, int HP, int cx, int cy) {
int X, Y, W, H;
if (Fl_Graphics_Driver::prepare(pxm, XP, YP, WP, HP, cx, cy, X, Y, W, H)) return;
transparent_f_type fl_TransparentBlt = TransparentBlt();
@ -642,6 +657,7 @@ fl_uintptr_t Fl_GDI_Graphics_Driver::cache(Fl_Pixmap *img, int w, int h, const c
delete[] bitmap;
}
fl_end_offscreen();
*cache_scale(img) = Fl_Scalable_Graphics_Driver::scale();
return (fl_uintptr_t)id;
}

View File

@ -35,7 +35,7 @@
#include "Fl_GDI_Graphics_Driver.H"
void Fl_GDI_Graphics_Driver::line_style(int style, int width, char* dashes) {
void Fl_GDI_Graphics_Driver::line_style_unscaled(int style, float width, char* dashes) {
// According to Bill, the "default" cap and join should be the
// "fastest" mode supported for the platform. I don't know why

View File

@ -35,11 +35,11 @@
// --- line and polygon drawing with integer coordinates
void Fl_GDI_Graphics_Driver::point(int x, int y) {
void Fl_GDI_Graphics_Driver::point_unscaled(float x, float y) {
SetPixel(gc_, x, y, fl_RGB());
}
void Fl_GDI_Graphics_Driver::rect(int x, int y, int w, int h) {
void Fl_GDI_Graphics_Driver::rect_unscaled(float x, float y, float w, float h) {
if (w<=0 || h<=0) return;
MoveToEx(gc_, x, y, 0L);
LineTo(gc_, x+w-1, y);
@ -59,7 +59,7 @@ void Fl_GDI_Graphics_Driver::focus_rect(int x, int y, int w, int h) {
for (yy = h; yy > 0; yy--, i++) if (i & 1) point(x, y + yy);
}
void Fl_GDI_Graphics_Driver::rectf(int x, int y, int w, int h) {
void Fl_GDI_Graphics_Driver::rectf_unscaled(float x, float y, float w, float h) {
if (w<=0 || h<=0) return;
RECT rect;
rect.left = x; rect.top = y;
@ -67,24 +67,24 @@ void Fl_GDI_Graphics_Driver::rectf(int x, int y, int w, int h) {
FillRect(gc_, &rect, fl_brush());
}
void Fl_GDI_Graphics_Driver::line(int x, int y, int x1, int y1) {
void Fl_GDI_Graphics_Driver::line_unscaled(float x, float y, float x1, float y1) {
MoveToEx(gc_, x, y, 0L);
LineTo(gc_, x1, y1);
SetPixel(gc_, x1, y1, fl_RGB());
}
void Fl_GDI_Graphics_Driver::line(int x, int y, int x1, int y1, int x2, int y2) {
void Fl_GDI_Graphics_Driver::line_unscaled(float x, float y, float x1, float y1, float x2, float y2) {
MoveToEx(gc_, x, y, 0L);
LineTo(gc_, x1, y1);
LineTo(gc_, x2, y2);
SetPixel(gc_, x2, y2, fl_RGB());
}
void Fl_GDI_Graphics_Driver::xyline(int x, int y, int x1) {
void Fl_GDI_Graphics_Driver::xyline_unscaled(float x, float y, float x1) {
MoveToEx(gc_, x, y, 0L); LineTo(gc_, x1+1, y);
}
void Fl_GDI_Graphics_Driver::xyline(int x, int y, int x1, int y2) {
void Fl_GDI_Graphics_Driver::xyline_unscaled(float x, float y, float x1, float y2) {
if (y2 < y) y2--;
else y2++;
MoveToEx(gc_, x, y, 0L);
@ -92,7 +92,7 @@ void Fl_GDI_Graphics_Driver::xyline(int x, int y, int x1, int y2) {
LineTo(gc_, x1, y2);
}
void Fl_GDI_Graphics_Driver::xyline(int x, int y, int x1, int y2, int x3) {
void Fl_GDI_Graphics_Driver::xyline_unscaled(float x, float y, float x1, float y2, float x3) {
if(x3 < x1) x3--;
else x3++;
MoveToEx(gc_, x, y, 0L);
@ -101,13 +101,13 @@ void Fl_GDI_Graphics_Driver::xyline(int x, int y, int x1, int y2, int x3) {
LineTo(gc_, x3, y2);
}
void Fl_GDI_Graphics_Driver::yxline(int x, int y, int y1) {
void Fl_GDI_Graphics_Driver::yxline_unscaled(float x, float y, float y1) {
if (y1 < y) y1--;
else y1++;
MoveToEx(gc_, x, y, 0L); LineTo(gc_, x, y1);
}
void Fl_GDI_Graphics_Driver::yxline(int x, int y, int y1, int x2) {
void Fl_GDI_Graphics_Driver::yxline_unscaled(float x, float y, float y1, float x2) {
if (x2 > x) x2++;
else x2--;
MoveToEx(gc_, x, y, 0L);
@ -115,7 +115,7 @@ void Fl_GDI_Graphics_Driver::yxline(int x, int y, int y1, int x2) {
LineTo(gc_, x2, y1);
}
void Fl_GDI_Graphics_Driver::yxline(int x, int y, int y1, int x2, int y3) {
void Fl_GDI_Graphics_Driver::yxline_unscaled(float x, float y, float y1, float x2, float y3) {
if(y3<y1) y3--;
else y3++;
MoveToEx(gc_, x, y, 0L);
@ -124,14 +124,14 @@ void Fl_GDI_Graphics_Driver::yxline(int x, int y, int y1, int x2, int y3) {
LineTo(gc_, x2, y3);
}
void Fl_GDI_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2) {
void Fl_GDI_Graphics_Driver::loop_unscaled(float x, float y, float x1, float y1, float x2, float y2) {
MoveToEx(gc_, x, y, 0L);
LineTo(gc_, x1, y1);
LineTo(gc_, x2, y2);
LineTo(gc_, x, y);
}
void Fl_GDI_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) {
void Fl_GDI_Graphics_Driver::loop_unscaled(float x, float y, float x1, float y1, float x2, float y2, float x3, float y3) {
MoveToEx(gc_, x, y, 0L);
LineTo(gc_, x1, y1);
LineTo(gc_, x2, y2);
@ -139,7 +139,7 @@ void Fl_GDI_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2,
LineTo(gc_, x, y);
}
void Fl_GDI_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2) {
void Fl_GDI_Graphics_Driver::polygon_unscaled(float x, float y, float x1, float y1, float x2, float y2) {
POINT p[3];
p[0].x = x; p[0].y = y;
p[1].x = x1; p[1].y = y1;
@ -148,7 +148,7 @@ void Fl_GDI_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y
Polygon(gc_, p, 3);
}
void Fl_GDI_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3) {
void Fl_GDI_Graphics_Driver::polygon_unscaled(float x, float y, float x1, float y1, float x2, float y2, float x3, float y3) {
POINT p[4];
p[0].x = x; p[0].y = y;
p[1].x = x1; p[1].y = y1;
@ -244,8 +244,10 @@ void Fl_GDI_Graphics_Driver::pop_clip() {
void Fl_GDI_Graphics_Driver::restore_clip() {
fl_clip_state_number++;
if (gc_) {
Fl_Region r = rstack[rstackptr];
SelectClipRgn(gc_, r); // if r is NULL, clip is automatically cleared
HRGN r = NULL;
if (rstack[rstackptr]) r = scale_clip(scale_);
SelectClipRgn(gc_, rstack[rstackptr]); // if region is NULL, clip is automatically cleared
if (r) unscale_clip(r);
}
}

View File

@ -32,14 +32,6 @@
#include <FL/math.h>
void Fl_GDI_Graphics_Driver::transformed_vertex(double xf, double yf) {
transformed_vertex0(int(rint(xf)), int(rint(yf)));
}
void Fl_GDI_Graphics_Driver::vertex(double x,double y) {
transformed_vertex0(int(x*m.a + y*m.c + m.x), int(x*m.b + y*m.d + m.y));
}
void Fl_GDI_Graphics_Driver::end_points() {
for (int i=0; i<n; i++) SetPixel(gc_, p[i].x, p[i].y, fl_RGB());
}
@ -54,7 +46,7 @@ void Fl_GDI_Graphics_Driver::end_line() {
void Fl_GDI_Graphics_Driver::end_loop() {
fixloop();
if (n>2) transformed_vertex((int)p[0].x, (int)p[0].y);
if (n>2) transformed_vertex0(p[0].x, p[0].y);
end_line();
}
@ -79,7 +71,7 @@ void Fl_GDI_Graphics_Driver::begin_complex_polygon() {
void Fl_GDI_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((int)p[gap_].x, (int)p[gap_].y);
transformed_vertex0(p[gap_].x, p[gap_].y);
counts[numcount++] = n-gap_;
gap_ = n;
} else {
@ -99,15 +91,7 @@ void Fl_GDI_Graphics_Driver::end_complex_polygon() {
}
}
// 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_GDI_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));
void Fl_GDI_Graphics_Driver::ellipse_unscaled(double xt, double yt, double rx, double ry) {
int llx = (int)rint(xt-rx);
int w = (int)rint(xt+rx)-llx;
int lly = (int)rint(yt-ry);

View File

@ -27,7 +27,6 @@
#include <windows.h>
class Fl_GDI_Image_Surface_Driver : public Fl_Image_Surface_Driver {
friend class Fl_Image_Surface;
virtual void end_current_(Fl_Surface_Device*);
public:
Fl_Surface_Device *previous;
@ -51,8 +50,14 @@ Fl_Image_Surface_Driver *Fl_Image_Surface_Driver::newImageSurfaceDriver(int w, i
Fl_GDI_Image_Surface_Driver::Fl_GDI_Image_Surface_Driver(int w, int h, int high_res, Fl_Offscreen off) : Fl_Image_Surface_Driver(w, h, high_res, 0) {
previous = 0;
float d = fl_graphics_driver->scale();
if (!off && d != 1 && high_res) {
w = int(w*d);
h = int(h*d);
}
offscreen = off ? off : CreateCompatibleBitmap( (fl_graphics_driver->gc() ? (HDC)fl_graphics_driver->gc() : fl_GetDC(0) ) , w, h);
driver(new Fl_GDI_Graphics_Driver);
if (d != 1 && high_res) driver()->scale(d);
_sgc = NULL;
}

View File

@ -3,7 +3,7 @@
//
// implementation of class Fl_Gl_Device_Plugin for the Fast Light Tool Kit (FLTK).
//
// Copyright 2010-2014 by Bill Spitzak and others.
// Copyright 2010-2017 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
@ -94,6 +94,8 @@ Fl_RGB_Image* Fl_OpenGL_Display_Device::capture_gl_rectangle(Fl_Gl_Window* glw,
# pragma message "FL_PORTING: check whether the default Fl_OpenGL_Display_Device::capture_gl_rectangle() works for your platform"
#endif
#include <FL/Fl_Screen_Driver.H>
#include <FL/Fl_Window_Driver.H>
Fl_RGB_Image* Fl_OpenGL_Display_Device::capture_gl_rectangle(Fl_Gl_Window *glw, int x, int y, int w, int h)
/* captures a rectangle of a Fl_Gl_Window window, and returns it as a RGB image
*/
@ -106,6 +108,12 @@ Fl_RGB_Image* Fl_OpenGL_Display_Device::capture_gl_rectangle(Fl_Gl_Window *glw,
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
glPixelStorei(GL_PACK_SKIP_ROWS, 0);
glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
//
int ns = glw->driver()->screen_num();
float s = Fl::screen_driver()->scale(ns);
if (s != 1) {
x *= s; y *= s; w *= s; h *= s;
}
// Read a block of pixels from the frame buffer
int mByteWidth = w * 3;
mByteWidth = (mByteWidth + 3) & ~3; // Align to 4 bytes

View File

@ -78,6 +78,13 @@ public:
virtual void disable_im();
virtual void open_display();
virtual void offscreen_size(Fl_Offscreen off, int &width, int &height);
virtual APP_SCALING_CAPABILITY rescalable() { return SYSTEMWIDE_APP_SCALING; }
virtual float scale(int n) {return scale_;}
virtual void scale(int n, float f) { scale_ = f;}
virtual float desktop_scale_factor();
private:
float scale_;
};

View File

@ -617,6 +617,9 @@ Fl_WinAPI_Screen_Driver::read_win_rectangle(uchar *p, // I - Pixel buffer or NU
/** Returns the current desktop scaling factor (1.75 for example)
*/
float Fl_WinAPI_Screen_Driver::desktop_scaling_factor() {
#ifdef FLTK_HIDPI_SUPPORT
return 1;// this becomes useless if FLTK app are made DPI-aware by calling SetProcessDpiAwareness()
#else
// Compute the global desktop scaling factor: 1, 1.25, 1.5, 1.75, etc...
// This factor can be set in Windows 10 by
// "Change the size of text, apps and other items" in display settings.
@ -636,6 +639,7 @@ float Fl_WinAPI_Screen_Driver::desktop_scaling_factor() {
float scaling = dhr/float(hr);
scaling = int(scaling * 100 + 0.5)/100.; // round to 2 digits after decimal point
return scaling;
#endif // FLTK_HIDPI_SUPPORT
}
void Fl_WinAPI_Screen_Driver::offscreen_size(Fl_Offscreen off, int &width, int &height)

View File

@ -261,10 +261,11 @@ static HRGN bitmap2region(Fl_Image* image) {
void Fl_WinAPI_Window_Driver::draw_begin()
{
if (shape_data_) {
if ((shape_data_->lw_ != w() || shape_data_->lh_ != h()) && shape_data_->shape_) {
float s = Fl::screen_driver()->scale(screen_num());
if ((shape_data_->lw_ != s*w() || shape_data_->lh_ != s*h()) && shape_data_->shape_) {
// size of window has changed since last time
shape_data_->lw_ = w();
shape_data_->lh_ = h();
shape_data_->lw_ = s*w();
shape_data_->lh_ = s*h();
Fl_Image* temp = shape_data_->shape_->copy(shape_data_->lw_, shape_data_->lh_);
HRGN region = bitmap2region(temp);
SetWindowRgn(fl_xid(pWindow), region, TRUE); // the system deletes the region when it's no longer needed
@ -385,6 +386,7 @@ void Fl_WinAPI_Window_Driver::make_current() {
#endif // USE_COLORMAP
fl_graphics_driver->clip_region(0);
fl_graphics_driver->scale(Fl::screen_driver()->scale(0));
}
void Fl_WinAPI_Window_Driver::label(const char *name,const char *iname) {

View File

@ -4,7 +4,7 @@
// Definition of X11 Screen interface
// for the Fast Light Tool Kit (FLTK).
//
// Copyright 2010-2016 by Bill Spitzak and others.
// Copyright 2010-2017 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
@ -39,13 +39,27 @@ protected:
short y_org;
short width;
short height;
#if USE_XFT
float scale;
#endif
} FLScreenInfo;
FLScreenInfo screens[MAX_SCREENS];
float dpi[MAX_SCREENS][2];
int poll_or_select();
int poll_or_select_with_delay(double time_to_wait);
int get_mouse_unscaled(int &xx, int &yy);
public:
#if USE_XFT // scaling does not work without Xft
virtual APP_SCALING_CAPABILITY rescalable() { return PER_SCREEN_APP_SCALING; }
virtual float scale(int n) {return screens[n].scale;}
virtual void scale(int n, float f) { screens[n].scale = f;}
virtual float desktop_scale_factor();
int screen_num_unscaled(int x, int y);
int screen_num_unscaled(int x, int y, int w, int h);
virtual void screen_xywh(int &X, int &Y, int &W, int &H);
#endif
static int ewmh_supported();
static void copy_image(const unsigned char* data, int W, int H, int destination);
// --- display management

View File

@ -3,7 +3,7 @@
//
// Definition of X11 Screen interface
//
// Copyright 1998-2016 by Bill Spitzak and others.
// Copyright 1998-2017 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
@ -20,9 +20,14 @@
#include "../../config_lib.h"
#include "Fl_X11_Screen_Driver.H"
#include "../Xlib/Fl_Font.H"
#include "Fl_X11_Window_Driver.H"
#include "../Xlib/Fl_Xlib_Graphics_Driver.H"
#include <FL/Fl.H>
#include <FL/x.H>
#include <FL/fl_ask.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_Image_Surface.H>
#include <FL/Fl_Tooltip.H>
#include <sys/time.h>
@ -229,10 +234,15 @@ void Fl_X11_Screen_Driver::init_workarea()
}
else
{
fl_workarea_xywh[0] = (int)xywh[0];
fl_workarea_xywh[1] = (int)xywh[1];
fl_workarea_xywh[2] = (int)xywh[2];
fl_workarea_xywh[3] = (int)xywh[3];
#if USE_XFT
float s = screens[0].scale;
#else
float s = 1;
#endif
fl_workarea_xywh[0] = xywh[0] / s;
fl_workarea_xywh[1] = xywh[1] / s;
fl_workarea_xywh[2] = xywh[2] / s;
fl_workarea_xywh[3] = xywh[3] / s;
}
if ( xywh ) { XFree(xywh); xywh = 0; }
}
@ -316,7 +326,9 @@ void Fl_X11_Screen_Driver::init() {
screens[i].y_org = xsi[i].y_org;
screens[i].width = xsi[i].width;
screens[i].height = xsi[i].height;
#if USE_XFT
screens[i].scale = 1;
#endif
if (dpi_by_randr) {
dpi[i][0] = dpih;
dpi[i][1] = dpiv;
@ -341,7 +353,9 @@ void Fl_X11_Screen_Driver::init() {
screens[i].y_org = 0;
screens[i].width = DisplayWidth(fl_display, i);
screens[i].height = DisplayHeight(fl_display, i);
#if USE_XFT
screens[i].scale = 1;
#endif
if (dpi_by_randr) {
dpi[i][0] = dpih;
dpi[i][1] = dpiv;
@ -353,6 +367,17 @@ void Fl_X11_Screen_Driver::init() {
}
}
}
/*#if __APPLE_CC__ && USE_XFT // TMP simulate 2 screens under XQuartz
if (strstr(getenv("DISPLAY"), "xquartz")) {
num_screens = 2;
screens[1].x_org = screens[0].width/2;;
screens[1].y_org = screens[0].y_org;
screens[1].width = screens[0].width = screens[0].width/2;
screens[1].height = screens[0].height;
screens[1].scale = screens[0].scale = 1;
}
#endif*/
init_workarea();
}
@ -379,10 +404,15 @@ void Fl_X11_Screen_Driver::screen_xywh(int &X, int &Y, int &W, int &H, int n)
n = 0;
if (num_screens > 0) {
X = screens[n].x_org;
Y = screens[n].y_org;
W = screens[n].width;
H = screens[n].height;
#if USE_XFT
float s = screens[n].scale;
#else
float s = 1;
#endif
X = screens[n].x_org / s;
Y = screens[n].y_org / s;
W = screens[n].width / s;
H = screens[n].height / s;
}
}
@ -765,26 +795,29 @@ Fl_RGB_Image *Fl_X11_Screen_Driver::read_win_rectangle(uchar *p, int X, int Y, i
image = 0;
# endif // __sgi
float s = Fl_Surface_Device::surface()->driver()->scale();
if (!image) {
// fetch absolute coordinates
int dx, dy, sx, sy, sw, sh;
Window child_win;
Fl_Window *win;
if (allow_outside) win = (Fl_Window*)1;
if (allow_outside) win = Fl_Window::current();
else win = fl_find(fl_window);
if (win) {
XTranslateCoordinates(fl_display, fl_window,
RootWindow(fl_display, fl_screen), X, Y, &dx, &dy, &child_win);
RootWindow(fl_display, fl_screen), X*s, Y*s, &dx, &dy, &child_win);
dx /= s; dy /= s;
// screen dimensions
Fl::screen_xywh(sx, sy, sw, sh, fl_screen);
Fl::screen_xywh(sx, sy, sw, sh, win->driver()->screen_num());
}
if (!win || (dx >= sx && dy >= sy && dx + w <= sx+sw && dy + h <= sy+sh)) {
// the image is fully contained, we can use the traditional method
// however, if the window is obscured etc. the function will still fail. Make sure we
// catch the error and continue, otherwise an exception will be thrown.
XErrorHandler old_handler = XSetErrorHandler(xgetimageerrhandler);
image = XGetImage(fl_display, fl_window, X, Y, w, h, AllPlanes, ZPixmap);
image = XGetImage(fl_display, fl_window, int(X*s), int(Y*s), w*s < 1 ? 1 : int(w*s), h*s < 1 ? 1 : int(h*s), AllPlanes, ZPixmap);
XSetErrorHandler(old_handler);
} else {
// image is crossing borders, determine visible region
@ -795,17 +828,17 @@ Fl_RGB_Image *Fl_X11_Screen_Driver::read_win_rectangle(uchar *p, int X, int Y, i
// allocate the image
int bpp = fl_visual->depth + ((fl_visual->depth / 8) % 2) * 8;
char* buf = (char*)malloc(bpp / 8 * w * h);
char* buf = (char*)malloc(bpp / 8 * int(w*s) * int(h*s));
image = XCreateImage(fl_display, fl_visual->visual,
fl_visual->depth, ZPixmap, 0, buf, w, h, bpp, 0);
fl_visual->depth, ZPixmap, 0, buf, w*s, h*s, bpp, 0);
if (!image) {
if (buf) free(buf);
return 0;
}
XErrorHandler old_handler = XSetErrorHandler(xgetimageerrhandler);
XImage *subimg = XGetSubImage(fl_display, fl_window, X + noffx, Y + noffy,
nw, nh, AllPlanes, ZPixmap, image, noffx, noffy);
XImage *subimg = XGetSubImage(fl_display, fl_window, (X + noffx)*s, (Y + noffy)*s,
nw*s, nh*s, AllPlanes, ZPixmap, image, noffx*s, noffy*s);
XSetErrorHandler(old_handler);
if (!subimg) {
XDestroyImage(image);
@ -815,6 +848,10 @@ Fl_RGB_Image *Fl_X11_Screen_Driver::read_win_rectangle(uchar *p, int X, int Y, i
}
if (!image) return 0;
if (s != 1) {
w = w*s < 1 ? 1 : int(w*s);
h = h*s < 1 ? 1 : int(h*s);
}
#ifdef DEBUG
printf("width = %d\n", image->width);
@ -1154,6 +1191,244 @@ void Fl_X11_Screen_Driver::offscreen_size(Fl_Offscreen off, int &width, int &hei
height = (int)h;
}
#if USE_XFT
int Fl_X11_Screen_Driver::screen_num_unscaled(int x, int y)
{
int screen = 0;
if (num_screens < 0) init();
for (int i = 0; i < num_screens; i ++) {
int sx = screens[i].x_org, sy = screens[i].y_org, sw = screens[i].width, sh = screens[i].height;
if ((x >= sx) && (x < (sx+sw)) && (y >= sy) && (y < (sy+sh))) {
screen = i;
break;
}
}
return screen;
}
int Fl_X11_Screen_Driver::screen_num_unscaled(int x, int y, int w, int h)
{
int best_screen = 0;
float best_intersection = 0.;
if (num_screens < 0) init();
for (int i = 0; i < num_screens; i++) {
float sintersection = fl_intersection(x, y, w, h, screens[i].x_org, screens[i].y_org,
screens[i].width, screens[i].height);
if (sintersection > best_intersection) {
best_screen = i;
best_intersection = sintersection;
}
}
return best_screen;
}
#endif
#if USE_XFT
void Fl_X11_Screen_Driver::screen_xywh(int &X, int &Y, int &W, int &H)
{
int xx, yy;
int ns = get_mouse_unscaled(xx,yy);
float s = screens[ns].scale;
X = screens[ns].x_org / s;
Y = screens[ns].y_org / s;
W = screens[ns].width / s;
H = screens[ns].height / s;
}
#if HAVE_DLSYM && HAVE_DLFCN_H
// returns true when schema is among the list of available schemas
static bool is_schema_valid(const char *schema, const char **known) {
int i = 0;
while (known[i]) {
if (strcmp(known[i++], schema) == 0) return true;
}
return false;
}
/*
returns true under Ubuntu or Debian or FreeBSD and when the gnome scaling value has been found
Ubuntu:
Change the gnome scaling factor with:
System Settings ==> Displays ==> Scale for menu and title bars
Read the current gnome scaling factor with:
gsettings get com.ubuntu.user-interface scale-factor
Example value: {'VGA-0': 10}
Its type is "a{si}". This value should be divided by 8 to get the correct scaling factor.
Debian or FreeBSD :
Change the gnome scaling factor with:
Tweak tools ==> Windows ==> Window scaling
Read the current gnome scaling factor with:
gsettings get org.gnome.settings-daemon.plugins.xsettings overrides
Example value: {'Gdk/WindowScalingFactor': <2>}
Its type is "a{sv}" and v itself is of type i
It's also possible to use 'Tweak tools' under Ubuntu. With the standard Ubuntu desktop,
the modified value goes to "org.gnome.settings-daemon.plugins.xsettings" as above.
With Gnome session flashback under Ubuntu 'Tweak tools' puts the scaling value (1 or 2)
in "org.gnome.desktop.interface scaling-factor".
Read the current gnome scaling factor with:
gsettings get org.gnome.desktop.interface scaling-factor
Its type is "u"
Thus, under Ubuntu, we read the 3 possible factor values and
return the first value different from 1 to get the scaling factor.
=================================================================================================
Ubuntu | default ubuntu desktop | System Settings => Displays => Scale for menu and title bars
com.ubuntu.user-interface scale-factor
-----------------------
Tweak tools => Windows => Window scaling
org.gnome.settings-daemon.plugins.xsettings overrides
-----------------------
Gnome session flashback | System Settings => Displays => Scale for menu and title bars
no effect
-----------------------
Tweak tools => Windows => Window scaling
org.gnome.desktop.interface scaling-factor
=================================================================================================
Debian or FreeBSD | gnome | Tweak tools => Windows => Window scaling
org.gnome.settings-daemon.plugins.xsettings overrides
=================================================================================================
*/
static bool gnome_scale_factor(float& factor) {
// define types needed for dynamic lib functions
typedef const char** (*g_settings_list_schemas_ftype)(void);
typedef void* (*g_settings_new_ftype)(const char *);
typedef void* (*g_settings_get_value_ftype)(void *settings, const char *key);
typedef void (*g_variant_get_ftype)(void *value, const char *format_string, ...);
typedef bool (*g_variant_iter_loop_ftype)(void *iter, const char *format_string, ...);
typedef void (*pter_ftype)(void*);
//typedef void* (*g_variant_get_type_ftype)(void *variant);
// open dynamic libs
void *glib = dlopen("libglib-2.0.so", RTLD_LAZY);
void *gio = dlopen("libgio-2.0.so", RTLD_LAZY);
void *gobj = dlopen("libgobject-2.0.so", RTLD_LAZY);
//fprintf(stderr,"glib=%p gio=%p gobj=%p\n",glib,gio,gobj);
if (!glib || !gio || !gobj) return false;
bool ubuntu = false;
// determine whether we run Ubuntu
char line[400] = "";
FILE *in = fopen("/proc/version", "r");
if (in) {
fgets(line, sizeof(line), in);
fclose(in);
if (strstr(line, "Ubuntu")) ubuntu = true;
}
// define pters to used functions
g_settings_list_schemas_ftype g_settings_list_schemas_f = (g_settings_list_schemas_ftype)dlsym(gio, "g_settings_list_schemas"); // 2.26
g_settings_new_ftype g_settings_new_f = (g_settings_new_ftype)dlsym(gio, "g_settings_new"); // 2.26
g_settings_get_value_ftype g_settings_get_value_f =
(g_settings_get_value_ftype)dlsym(gio, "g_settings_get_value"); // 2.26
if (!g_settings_list_schemas_f || !g_settings_new_f || !g_settings_get_value_f) return false;
g_variant_get_ftype g_variant_get_f = (g_variant_get_ftype)dlsym(glib, "g_variant_get"); //2.24
g_variant_iter_loop_ftype g_variant_iter_loop_f = (g_variant_iter_loop_ftype)dlsym(glib, "g_variant_iter_loop"); // 2.24
pter_ftype g_variant_iter_free_f = (pter_ftype)dlsym(glib, "g_variant_iter_free"); // 2.24
pter_ftype g_object_unref_f = (pter_ftype)dlsym(gobj, "g_object_unref");
pter_ftype g_variant_unref_f = (pter_ftype)dlsym(glib, "g_variant_unref"); // 2.24
//g_variant_get_type_ftype g_variant_get_type_f = (g_variant_get_type_ftype)dlsym(glib, "g_variant_get_type"); // 2.24
// call dynamic lib functions
const char **known = g_settings_list_schemas_f(); // list of available GSettings schemas
const char *schema;
float ubuntu_f = 1, ubuntu_desktop_f = 1, gnome_f = 1;
bool found = false;
if (ubuntu) {
schema = "com.ubuntu.user-interface";
if (is_schema_valid(schema, known)) {
found = true;
void *gset = g_settings_new_f(schema);
void *gvar = g_settings_get_value_f(gset, "scale-factor");
void *iter;
char str[10], *str2; int v=8, v2;
g_variant_get_f(gvar, "a{si}", &iter);
while (g_variant_iter_loop_f(iter, "{si}", &str2, &v2)) { // read the last couple of values
strcpy(str, str2); v = v2;
}
ubuntu_f = v/8.;
printf("com.ubuntu.user-interface scale-factor name=%s value=%d factor=%g\n", str, v, ubuntu_f);
g_variant_iter_free_f(iter);
g_variant_unref_f(gvar);
g_object_unref_f(gset);
if (ubuntu_f != 1) {
factor = ubuntu_f;
return true;
}
}
schema = "org.gnome.desktop.interface";
if (is_schema_valid(schema, known)) {
found = true;
void *gset = g_settings_new_f(schema);
void *gvar = g_settings_get_value_f(gset, "scaling-factor");
unsigned v;
g_variant_get_f(gvar, "u", &v);
ubuntu_desktop_f = v;
printf("org.gnome.desktop.interface scaling-factor value=%u factor=%g\n", v, ubuntu_desktop_f);
g_variant_unref_f(gvar);
g_object_unref_f(gset);
if (ubuntu_desktop_f != 1) {
factor = ubuntu_desktop_f;
return true;
}
}
}
schema = "org.gnome.settings-daemon.plugins.xsettings";
if (is_schema_valid(schema, known)) {
void *gset = g_settings_new_f(schema);
void *gvar = g_settings_get_value_f(gset, "overrides");
void *iter;
char *str; int v;
//str = (char*)g_variant_get_type_f(gvar); // -> "a{sv}"
g_variant_get_f(gvar, "a{sv}", &iter);
g_variant_unref_f(gvar);
gvar = NULL;
while (g_variant_iter_loop_f(iter, "{sv}", &str, &gvar)) {
if (strstr(str, "WindowScalingFactor") == NULL) continue;
found = true;
//str = (char*)g_variant_get_type_f(gvar); // -> "i"
g_variant_get_f(gvar, "i", &v);
gnome_f = v;
printf("org.gnome.settings-daemon.plugins.xsettings overrides name=%s value=%d factor=%g\n", str, v, gnome_f);
free(str);
break;
}
g_variant_iter_free_f(iter);
if (gvar) g_variant_unref_f(gvar);
g_object_unref_f(gset);
}
if (!found) return false;
//factor = ubuntu_f * ubuntu_desktop_f * gnome_f;
factor = gnome_f;
return true;
}
#endif // HAVE_DLSYM && HAVE_DLFCN_H
// return the desktop's default scaling value
float Fl_X11_Screen_Driver::desktop_scale_factor()
{
float factor = 1;
#if HAVE_DLSYM && HAVE_DLFCN_H
gnome_scale_factor(factor);
#endif
return factor;
}
#endif // USE_XFT
//
// End of "$Id$".
//

View File

@ -4,7 +4,7 @@
// Definition of X11 window driver
// for the Fast Light Tool Kit (FLTK).
//
// Copyright 2010-2016 by Bill Spitzak and others.
// Copyright 2010-2017 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
@ -27,6 +27,7 @@
#include <FL/Fl_Window_Driver.H>
#include <config.h> // for USE_XDBE
#include <FL/x.H> // for Cursor
class Fl_Bitmap;
/*
@ -56,6 +57,8 @@ struct Fl_Window_Driver::shape_data_type {
class FL_EXPORT Fl_X11_Window_Driver : public Fl_Window_Driver
{
friend class Fl_X;
friend class Fl_X11_Screen_Driver;
friend int fl_handle(const XEvent&);
private:
struct icon_data {
@ -63,6 +66,17 @@ private:
Fl_RGB_Image **icons;
int count;
} *icon_;
Cursor current_cursor_;
#if USE_XFT
// --- support for screen-specific scaling factors
struct type_for_resize_window_between_screens {
int screen;
bool busy;
};
static type_for_resize_window_between_screens data_for_resize_window_between_screens_;
int screen_num_;
void screen_num(int n) { screen_num_ = n; }
#endif // USE_XFT
void decorated_win_size(int &w, int &h);
void combine_mask();
void shape_bitmap_(Fl_Image* b);
@ -79,7 +93,11 @@ public:
Fl_X11_Window_Driver(Fl_Window*);
virtual ~Fl_X11_Window_Driver();
static inline Fl_X11_Window_Driver* driver(Fl_Window *w) {return (Fl_X11_Window_Driver*)w->driver();}
#if USE_XFT
virtual int screen_num();
static void resize_after_screen_change(void *data);
#endif // USE_XFT
// --- window data
virtual int decorated_w();
virtual int decorated_h();

View File

@ -3,7 +3,7 @@
//
// Definition of X11 window driver.
//
// Copyright 1998-2016 by Bill Spitzak and others.
// Copyright 1998-2017 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
@ -112,11 +112,11 @@ void Fl_X11_Window_Driver::destroy_double_buffer() {
#if USE_XDBE
if (can_xdbe()) {
XdbeDeallocateBackBufferName(fl_display, other_xid);
other_xid = 0;
}
else
#endif // USE_XDBE
Fl_Window_Driver::destroy_double_buffer();
fl_delete_offscreen(other_xid);
other_xid = 0;
}
Fl_Window_Driver *Fl_Window_Driver::newWindowDriver(Fl_Window *w)
@ -130,6 +130,10 @@ Fl_X11_Window_Driver::Fl_X11_Window_Driver(Fl_Window *win)
{
icon_ = new icon_data;
memset(icon_, 0, sizeof(icon_data));
current_cursor_ = None;
#if USE_XFT
screen_num_ = -1;
#endif
}
@ -160,8 +164,10 @@ void Fl_X11_Window_Driver::decorated_win_size(int &w, int &h)
if (status == 0 || root == parent) return;
XWindowAttributes attributes;
XGetWindowAttributes(fl_display, parent, &attributes);
w = attributes.width;
h = attributes.height;
int nscreen = screen_num();
float s = Fl::screen_driver()->scale(nscreen);
w = attributes.width / s;
h = attributes.height / s;
}
@ -196,7 +202,9 @@ void Fl_X11_Window_Driver::take_focus()
void Fl_X11_Window_Driver::draw_begin()
{
if (shape_data_) {
if (( shape_data_->lw_ != w() || shape_data_->lh_ != h() ) && shape_data_->shape_) {
int nscreen = screen_num();
float s = Fl::screen_driver()->scale(nscreen);
if (( shape_data_->lw_ != int(s*w()) || shape_data_->lh_ != int(s*h()) ) && shape_data_->shape_) {
// size of window has changed since last time
combine_mask();
}
@ -324,8 +332,9 @@ void Fl_X11_Window_Driver::combine_mask()
#endif
}
if (!XShapeCombineMask_f) return;
shape_data_->lw_ = w();
shape_data_->lh_ = h();
float s = Fl::screen_driver()->scale(screen_num());
shape_data_->lw_ = w()*s;
shape_data_->lh_ = h()*s;
Fl_Image* temp = shape_data_->shape_->copy(shape_data_->lw_, shape_data_->lh_);
Pixmap pbitmap = XCreateBitmapFromData(fl_display, fl_xid(pWindow),
(const char*)*temp->data(),
@ -400,25 +409,30 @@ void Fl_X11_Window_Driver::capture_titlebar_and_borders(Fl_Shared_Image*& top, F
if (n) XFree(children);
if (!do_it) wsides = htop = 0;
int hbottom = wsides;
float s = Fl::screen_driver()->scale(screen_num());
htop /= s; wsides /= s;
fl_window = parent;
if (htop) {
r_top = Fl::screen_driver()->read_win_rectangle(NULL, 0, 0, - (w() + 2 * wsides), htop, 0);
top = Fl_Shared_Image::get(r_top);
top->scale(w() + 2 * wsides, htop, 0, 1);
}
if (wsides) {
r_left = Fl::screen_driver()->read_win_rectangle(NULL, 0, htop, -wsides, h(), 0);
if (r_left) {
left = Fl_Shared_Image::get(r_left);
left->scale(wsides, h(), 0, 1);
}
r_right = Fl::screen_driver()->read_win_rectangle(NULL, w() + wsides, htop, -wsides, h(), 0);
if (r_right) {
right = Fl_Shared_Image::get(r_right);
right->scale(wsides, h(), 0, 1);
}
r_bottom = Fl::screen_driver()->read_win_rectangle(NULL, 0, htop + h(), -(w() + 2*wsides), hbottom, 0);
if (r_bottom) {
bottom = Fl_Shared_Image::get(r_bottom);
}
}
bottom->scale(w() + 2*wsides, wsides, 0, 1);
} }
fl_window = from;
Fl_Surface_Device::pop_current();
}
@ -432,6 +446,9 @@ void Fl_X11_Window_Driver::make_current() {
}
fl_window = fl_xid(pWindow);
fl_graphics_driver->clip_region(0);
#if USE_XFT
((Fl_Xlib_Graphics_Driver*)fl_graphics_driver)->scale(Fl::screen_driver()->scale(screen_num()));
#endif
#ifdef FLTK_USE_CAIRO
// update the cairo_t context
@ -460,6 +477,7 @@ void Fl_X11_Window_Driver::hide() {
if (ip->region) Fl_Graphics_Driver::default_driver().XDestroyRegion(ip->region);
# if USE_XFT
Fl_Xlib_Graphics_Driver::destroy_xft_draw(ip->xid);
screen_num_ = -1;
# endif
// this test makes sure ip->xid has not been destroyed already
if (ip->xid) XDestroyWindow(fl_display, ip->xid);
@ -650,8 +668,9 @@ void Fl_X11_Window_Driver::erase_menu() {
int Fl_X11_Window_Driver::scroll(int src_x, int src_y, int src_w, int src_h, int dest_x, int dest_y,
void (*draw_area)(void*, int,int,int,int), void* data)
{
float s = Fl::screen_driver()->scale(screen_num());
XCopyArea(fl_display, fl_window, fl_window, (GC)fl_graphics_driver->gc(),
src_x, src_y, src_w, src_h, dest_x, dest_y);
int(src_x*s), int(src_y*s), int(src_w*s), int(src_h*s), int(dest_x*s), int(dest_y*s));
// we have to sync the display and get the GraphicsExpose events! (sigh)
for (;;) {
XEvent e; XWindowEvent(fl_display, fl_window, ExposureMask, &e);
@ -670,6 +689,40 @@ Fl_X *Fl_X11_Window_Driver::makeWindow()
return Fl_X::i(pWindow);
}
#if USE_XFT
Fl_X11_Window_Driver::type_for_resize_window_between_screens Fl_X11_Window_Driver::data_for_resize_window_between_screens_ = {0, false};
void Fl_X11_Window_Driver::resize_after_screen_change(void *data) {
Fl_Window *win = (Fl_Window*)data;
int oldx, oldy;
XWindowAttributes actual;
XGetWindowAttributes(fl_display, fl_xid(win), &actual);
Window cr;
XTranslateCoordinates(fl_display, fl_xid(win), actual.root, 0, 0, &oldx, &oldy, &cr);
win->hide();
float f = Fl::screen_driver()->scale(data_for_resize_window_between_screens_.screen);
Fl_X11_Window_Driver::driver(win)->screen_num(data_for_resize_window_between_screens_.screen);
win->position(oldx/f, oldy/f);
win->driver()->force_position(1);
Fl_Xlib_Graphics_Driver *d = (Fl_Xlib_Graphics_Driver*)Fl_Display_Device::display_device()->driver();
d->scale(f);
win->show();
win->wait_for_expose();
data_for_resize_window_between_screens_.busy = false;
}
int Fl_X11_Window_Driver::screen_num() {
if (pWindow->parent()) {
screen_num_ = pWindow->top_window()->driver()->screen_num();
}
return screen_num_ >= 0 ? screen_num_ : 0;
}
#endif // USE_XFT
//
// End of "$Id$".
//

View File

@ -51,6 +51,8 @@ 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) {
driver(new Fl_Xlib_Graphics_Driver());
float s = Fl_Graphics_Driver::default_driver().scale();
((Fl_Xlib_Graphics_Driver*)driver())->scale(s);
oldwindow = fl_window;
xid = fl_create_offscreen(w,h);
driver()->push_no_clip();
@ -65,10 +67,10 @@ Fl_Xlib_Copy_Surface_Driver::~Fl_Xlib_Copy_Surface_Driver() {
driver()->pop_clip();
bool need_push = (Fl_Surface_Device::surface() != this);
if (need_push) Fl_Surface_Device::push_current(this);
unsigned char *data = fl_read_image(NULL,0,0,width,height,0);
Fl_RGB_Image *rgb = Fl::screen_driver()->read_win_rectangle(NULL, 0, 0, width, height, 0);
if (need_push) Fl_Surface_Device::pop_current();
Fl_X11_Screen_Driver::copy_image(data, width, height, 1);
delete[] data;
Fl_X11_Screen_Driver::copy_image(rgb->array, rgb->w(), rgb->h(), 1);
delete rgb;
fl_delete_offscreen(xid);
delete driver();
}

View File

@ -43,7 +43,7 @@ struct _XRegion {
#endif // HAVE_X11_XREGION_H
#if USE_PANGO
#include <pango/pangoxft.h>
#include <pango/pango.h>
#endif
@ -52,11 +52,27 @@ struct _XRegion {
*
This class is implemented only on the Xlib platform.
*/
class FL_EXPORT Fl_Xlib_Graphics_Driver : public Fl_Graphics_Driver {
class FL_EXPORT Fl_Xlib_Graphics_Driver : public Fl_Scalable_Graphics_Driver {
private:
int offset_x_, offset_y_; // translation between user and graphical coordinates: graphical = user + offset
unsigned depth_; // depth of translation stack
int stack_x_[20], stack_y_[20]; // translation stack allowing cumulative translations
int line_delta_;
protected:
virtual void draw_unscaled(Fl_Pixmap *pxm, float s, int XP, int YP, int WP, int HP, int cx, int cy);
virtual void draw_unscaled(Fl_Bitmap *pxm, float s, int XP, int YP, int WP, int HP, int cx, int cy);
virtual void draw_unscaled(Fl_RGB_Image *img, float s, int XP, int YP, int WP, int HP, int cx, int cy);
virtual void draw_image_unscaled(const uchar* buf, int X,int Y,int W,int H, int D=3, int L=0);
virtual void draw_image_unscaled(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=3);
virtual void draw_image_mono_unscaled(const uchar* buf, int X,int Y,int W,int H, int D=1, int L=0);
virtual void draw_image_mono_unscaled(Fl_Draw_Image_Cb cb, void* data, int X,int Y,int W,int H, int D=1);
#if HAVE_XRENDER
virtual int draw_scaled(Fl_Image *img, int XP, int YP, int WP, int HP);
int scale_and_render_pixmap(Fl_Offscreen pixmap, int depth, double scale_x, double scale_y, int srcx, int srcy, int XP, int YP, int WP, int HP);
#endif
virtual int height_unscaled();
virtual int descent_unscaled();
virtual Region scale_clip(float f);
#if USE_XFT
void drawUCS4(const void *str, int n, int x, int y);
#endif
@ -65,16 +81,11 @@ private:
static PangoContext *pctxt_;
static PangoFontMap *pfmap_;
static PangoLayout *playout_;
protected:
PangoFontDescription *pfd_;
void do_draw(int from_right, const char *str, int n, int x, int y);
static PangoContext *context();
static void init_built_in_fonts();
#endif
#if HAVE_XRENDER
int scale_and_render_pixmap(Fl_Offscreen pixmap, int depth, double scale_x, double scale_y, int srcx, int srcy, int XP, int YP, int WP, int HP);
#endif
protected:
static GC gc_;
uchar **mask_bitmap_;
uchar **mask_bitmap() {return mask_bitmap_;}
@ -93,6 +104,7 @@ public:
virtual ~Fl_Xlib_Graphics_Driver();
void translate_all(int dx, int dy);
void untranslate_all();
virtual void scale(float f);
virtual int has_feature(driver_feature mask) { return mask & NATIVE; }
virtual void *gc() { return gc_; }
virtual void gc(void *value);
@ -104,51 +116,43 @@ public:
// --- bitmap stuff
Fl_Bitmask create_bitmask(int w, int h, const uchar *array);
void delete_bitmask(Fl_Bitmask bm);
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);
#if HAVE_XRENDER
int draw_scaled(Fl_Image *img, int XP, int YP, int WP, int HP);
#endif
virtual void draw_unscaled(const char* str, int n, int x, int y);
virtual void draw_unscaled(int angle, const char *str, int n, int x, int y);
virtual void rtl_draw_unscaled(const char* str, int n, int x, int y);
virtual void font_unscaled(Fl_Font face, Fl_Fontsize size);
fl_uintptr_t cache(Fl_Pixmap *img, int w, int h, const char *const*array);
fl_uintptr_t cache(Fl_Bitmap *img, int w, int h, const uchar *array);
void uncache(Fl_RGB_Image *img, fl_uintptr_t &id_, fl_uintptr_t &mask_);
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);
virtual double width_unscaled(const char *str, int n);
virtual double width_unscaled(unsigned int c);
virtual void text_extents_unscaled(const char*, int n, int& dx, int& dy, int& w, int& h);
virtual Fl_Fontsize size_unscaled();
virtual void copy_offscreen_unscaled(float x, float y, float w, float h, Fl_Offscreen pixmap, float srcx, float 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
void add_rectangle_to_region(Fl_Region r, int x, int y, int w, int h);
Fl_Region XRectangleRegion(int x, int y, int w, int h);
void XDestroyRegion(Fl_Region r);
protected:
virtual void transformed_vertex0(short x, short y);
virtual void transformed_vertex0(float x, float y);
void fixloop();
// --- 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);
virtual void point_unscaled(float x, float y);
virtual void rect_unscaled(float x, float y, float w, float h);
virtual void rectf_unscaled(float x, float y, float w, float h);
virtual void line_unscaled(float x, float y, float x1, float y1);
virtual void line_unscaled(float x, float y, float x1, float y1, float x2, float y2);
virtual void xyline_unscaled(float x, float y, float x1);
virtual void xyline_unscaled(float x, float y, float x1, float y2);
virtual void xyline_unscaled(float x, float y, float x1, float y2, float x3);
virtual void yxline_unscaled(float x, float y, float y1);
virtual void yxline_unscaled(float x, float y, float y1, float x2);
virtual void yxline_unscaled(float x, float y, float y1, float x2, float y3);
virtual void loop_unscaled(float x0, float y0, float x1, float y1, float x2, float y2);
virtual void loop_unscaled(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3);
virtual void polygon_unscaled(float x0, float y0, float x1, float y1, float x2, float y2);
virtual void polygon_unscaled(float x0, float y0, float x1, float y1, float x2, float y2, float x3, float 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);
@ -156,25 +160,18 @@ protected:
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);
virtual void ellipse_unscaled(double xt, double yt, double rx, double ry);
// --- 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
virtual void arc_unscaled(float x, float y, float w, float h, double a1, double a2);
virtual void pie_unscaled(float x, float y, float w, float h, double a1, double a2);
virtual void line_style_unscaled(int style, float width, char* dashes);
void color(Fl_Color c);
void set_color(Fl_Color i, unsigned int c);
void free_color(Fl_Color i, int overlay);

View File

@ -3,7 +3,7 @@
//
// Rectangle drawing routines for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2016 by Bill Spitzak and others.
// Copyright 1998-2017 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
@ -57,6 +57,7 @@ Fl_Xlib_Graphics_Driver::Fl_Xlib_Graphics_Driver(void) {
p_size = 0;
p = NULL;
line_width_ = 0;
line_delta_ = 0;
#if USE_PANGO
pfd_ = pango_font_description_new();
Fl_Graphics_Driver::font(0, 0);
@ -78,8 +79,30 @@ void Fl_Xlib_Graphics_Driver::gc(void *value) {
fl_gc = gc_;
}
void Fl_Xlib_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_, srcx, srcy, w, h, x+offset_x_, y+offset_y_);
void Fl_Xlib_Graphics_Driver::scale(float f) {
#if USE_XFT
if (f != scale_) {
size_ = 0;
scale_ = f;
//fprintf(stderr, "scale=%.2f\n", scale_);
line_style(FL_SOLID); // scale also default line width
/* Scaling >= 2 transforms 1-pixel wide lines into wider lines.
X11 draws 2-pixel wide lines so that half of the line width is above or at left
of a 1-pixel wide line that would be drawn with the same coordinates.
Thus, if the line starts at coordinates (0,0) half of the line width is invisible.
Similarly, if the line ends at w()-1 the last pixel of the window is not drawn.
What is wanted when scale_ == 2 is a visible 2-pixel wide line in the first case,
and a line at the window's edge in the 2nd case.
Setting line_delta_ to 1 and offsetting all line, rectangle, text and clip
coordinates by line_delta_ achieves what is wanted until scale_ <= 3.5.
*/
line_delta_ = (scale_ > 1.75 ? 1 : 0);
}
#endif
}
void Fl_Xlib_Graphics_Driver::copy_offscreen_unscaled(float x, float y, float w, float h, Fl_Offscreen pixmap, float srcx, float srcy) {
XCopyArea(fl_display, pixmap, fl_window, gc_, srcx, srcy, w, h, x+offset_x_*scale_, y+offset_y_*scale_);
}
void Fl_Xlib_Graphics_Driver::add_rectangle_to_region(Fl_Region r, int X, int Y, int W, int H) {
@ -88,7 +111,8 @@ void Fl_Xlib_Graphics_Driver::add_rectangle_to_region(Fl_Region r, int X, int Y,
XUnionRectWithRegion(&R, r, r);
}
void Fl_Xlib_Graphics_Driver::transformed_vertex0(short x, short y) {
void Fl_Xlib_Graphics_Driver::transformed_vertex0(float fx, float fy) {
short x = short(fx), y = short(fy);
if (!n || x != p[n-1].x || y != p[n-1].y) {
if (n >= p_size) {
p_size = p ? 2*p_size : 16;
@ -205,6 +229,25 @@ void Fl_Xlib_Graphics_Driver::font_name(int num, const char *name) {
s->first = 0;
}
Region Fl_Xlib_Graphics_Driver::scale_clip(float f) {
Region r = rstack[rstackptr];
if (r == 0 || (f == 1 && offset_x_ == 0 && offset_y_ == 0) ) return 0;
float delta = (f >= 2 ? f/3 : 0);
Region r2 = XCreateRegion();
XRectangle R;
for (int i = 0; i < r->numRects; i++) {
R.x = short((r->rects[i].x1 + offset_x_)*f-delta + line_delta_);
R.y = short((r->rects[i].y1 + offset_y_)*f-delta + line_delta_);
R.width = short(r->rects[i].x2*f) - short(r->rects[i].x1*f);
R.height = short(r->rects[i].y2*f) - short(r->rects[i].y1*f);
XUnionRectWithRegion(&R, r2, r2);
}
rstack[rstackptr] = r2;
return r;
}
void Fl_Xlib_Graphics_Driver::translate_all(int dx, int dy) { // reversibly adds dx,dy to the offset between user and graphical coordinates
stack_x_[depth_] = offset_x_;
stack_y_[depth_] = offset_y_;

View File

@ -3,7 +3,7 @@
//
// Arc (integer) drawing functions for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2016 by Bill Spitzak and others.
// Copyright 1998-2017 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
@ -26,15 +26,15 @@
\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) {
void Fl_Xlib_Graphics_Driver::arc_unscaled(float x,float y,float w,float h,double a1,double a2) {
if (w <= 0 || h <= 0) return;
XDrawArc(fl_display, fl_window, gc_, x+offset_x_,y+offset_y_,w-1,h-1, int(a1*64),int((a2-a1)*64));
XDrawArc(fl_display, fl_window, gc_, int(x+offset_x_*scale_), int(y+offset_y_*scale_), int(w-1), int(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) {
void Fl_Xlib_Graphics_Driver::pie_unscaled(float x,float y,float w,float h,double a1,double a2) {
if (w <= 0 || h <= 0) return;
x += offset_x_;
y += offset_y_;
x += offset_x_*scale_;
y += offset_y_*scale_;
XDrawArc(fl_display, fl_window, gc_, x,y,w-1,h-1, int(a1*64),int((a2-a1)*64));
XFillArc(fl_display, fl_window, gc_, x,y,w-1,h-1, int(a1*64),int((a2-a1)*64));
}

View File

@ -3,7 +3,7 @@
//
// X11 font utilities for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2016 by Bill Spitzak and others.
// Copyright 1998-2017 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
@ -596,7 +596,7 @@ XFontStruct* Fl_XFont_On_Demand::value() {
return ptr;
}
void Fl_Xlib_Graphics_Driver::font(Fl_Font fnum, Fl_Fontsize size) {
void Fl_Xlib_Graphics_Driver::font_unscaled(Fl_Font fnum, Fl_Fontsize size) {
if (fnum==-1) {
Fl_Graphics_Driver::font(0, 0);
return;
@ -611,27 +611,32 @@ void Fl_Xlib_Graphics_Driver::font(Fl_Font fnum, Fl_Fontsize size) {
}
}
int Fl_Xlib_Graphics_Driver::height() {
int Fl_Xlib_Graphics_Driver::height_unscaled() {
if (font_descriptor()) return font_descriptor()->font->ascent + font_descriptor()->font->descent;
else return -1;
}
int Fl_Xlib_Graphics_Driver::descent() {
int Fl_Xlib_Graphics_Driver::descent_unscaled() {
if (font_descriptor()) return font_descriptor()->font->descent;
else return -1;
}
double Fl_Xlib_Graphics_Driver::width(const char* c, int n) {
Fl_Fontsize Fl_Xlib_Graphics_Driver::size_unscaled() {
if (font_descriptor()) return size_;
return -1;
}
double Fl_Xlib_Graphics_Driver::width_unscaled(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) {
double Fl_Xlib_Graphics_Driver::width_unscaled(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) {
void Fl_Xlib_Graphics_Driver::text_extents_unscaled(const char *c, int n, int &dx, int &dy, int &W, int &H) {
if (font_gc != gc_) {
if (!font_descriptor()) font(FL_HELVETICA, FL_NORMAL_SIZE);
font_gc = gc_;
@ -649,7 +654,7 @@ void Fl_Xlib_Graphics_Driver::text_extents(const char *c, int n, int &dx, int &d
// dy = fl_descent() - H;
}
void Fl_Xlib_Graphics_Driver::draw(const char* c, int n, int x, int y) {
void Fl_Xlib_Graphics_Driver::draw_unscaled(const char* c, int n, int x, int y) {
if (font_gc != gc_) {
if (!font_descriptor()) this->font(FL_HELVETICA, FL_NORMAL_SIZE);
font_gc = gc_;
@ -658,7 +663,7 @@ void Fl_Xlib_Graphics_Driver::draw(const char* c, int n, int x, int y) {
if (gc_) XUtf8DrawString(fl_display, fl_window, font_descriptor()->font, gc_, x+offset_x_, y+offset_y_, c, n);
}
void Fl_Xlib_Graphics_Driver::draw(int angle, const char *str, int n, int x, int y) {
void Fl_Xlib_Graphics_Driver::draw_unscaled(int angle, const char *str, int n, int x, int y) {
static char warning = 0; // issue warning only once
if (!warning && angle != 0) {
warning = 1;
@ -669,7 +674,7 @@ void Fl_Xlib_Graphics_Driver::draw(int angle, const char *str, int n, int x, int
this->draw(str, n, (int)x, (int)y);
}
void Fl_Xlib_Graphics_Driver::rtl_draw(const char* c, int n, int x, int y) {
void Fl_Xlib_Graphics_Driver::rtl_draw_unscaled(const char* c, int n, int x, int y) {
if (font_gc != gc_) {
if (!font_descriptor()) this->font(FL_HELVETICA, FL_NORMAL_SIZE);
font_gc = gc_;

View File

@ -3,7 +3,7 @@
//
// More font utilities for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2016 by Bill Spitzak and others.
// Copyright 1998-2017 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
@ -125,6 +125,30 @@ static Fl_Fontdesc built_in_table[] = {
Fl_Fontdesc* fl_fonts = built_in_table;
Fl_Fontsize Fl_Xlib_Graphics_Driver::size_unscaled() {
return (Fl_Fontsize)(size_);
}
static void correct_extents (float scale_, int &dx, int &dy, int &w, int &h) {
if (int(scale_) == scale_) { // correct for extents non divisible by integral scale_
int delta = dx - int(dx/scale_)*scale_;
if (delta) {
dx -= delta; w += delta;
}
delta = -dy - int((-dy)/scale_)*scale_;
if (delta) {
dy -= delta; h += delta;
}
delta = h - int(h/scale_)*scale_;
if (delta) {
h += delta;
}
delta = w - int(w/scale_)*scale_;
if (delta) {
w += delta;
}
}
}
#if ! USE_PANGO
@ -455,8 +479,8 @@ Fl_Font Fl_Xlib_Graphics_Driver::set_fonts(const char* pattern_name)
static const char* fl_encoding_ = "iso10646-1";
void Fl_Xlib_Graphics_Driver::font(Fl_Font fnum, Fl_Fontsize size) {
fl_xft_font(this,fnum,size,0);
void Fl_Xlib_Graphics_Driver::font_unscaled(Fl_Font fnum, Fl_Fontsize size) {
fl_xft_font(this, fnum, size, 0);
}
static XftFont* fontopen(const char* name, /*Fl_Fontsize*/double size, bool core, int angle) {
@ -691,17 +715,17 @@ static void utf8extents(Fl_Font_Descriptor *desc, const char *str, int n, XGlyph
#endif
}
int Fl_Xlib_Graphics_Driver::height() {
int Fl_Xlib_Graphics_Driver::height_unscaled() {
if (font_descriptor()) return font_descriptor()->font->ascent + font_descriptor()->font->descent;
else return -1;
}
int Fl_Xlib_Graphics_Driver::descent() {
int Fl_Xlib_Graphics_Driver::descent_unscaled() {
if (font_descriptor()) return font_descriptor()->font->descent;
else return -1;
}
double Fl_Xlib_Graphics_Driver::width(const char* str, int n) {
double Fl_Xlib_Graphics_Driver::width_unscaled(const char* str, int n) {
if (!font_descriptor()) return -1.0;
XGlyphInfo i;
utf8extents(font_descriptor(), str, n, &i);
@ -715,11 +739,12 @@ static double fl_xft_width(Fl_Font_Descriptor *desc, FcChar32 *str, int n) {
return i.xOff;
}
double Fl_Xlib_Graphics_Driver::width(unsigned int c) {
double Fl_Xlib_Graphics_Driver::width_unscaled(unsigned int c) {
if (!font_descriptor()) return -1.0;
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) {
void Fl_Xlib_Graphics_Driver::text_extents_unscaled(const char *c, int n, int &dx, int &dy, int &w, int &h) {
if (!font_descriptor()) {
w = h = 0;
dx = dy = 0;
@ -730,15 +755,12 @@ void Fl_Xlib_Graphics_Driver::text_extents(const char *c, int n, int &dx, int &d
w = gi.width;
h = gi.height;
dx = -gi.x;
dy = -gi.y;
} // fl_text_extents
dx = -gi.x + line_delta_;
dy = -gi.y + line_delta_;
correct_extents(scale_, dx, dy, w, h);
}
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);
}
void Fl_Xlib_Graphics_Driver::draw_unscaled(const char *str, int n, int x, int y) {
#if USE_OVERLAY
XftDraw*& draw_ = fl_overlay ? draw_overlay : ::draw_;
if (fl_overlay) {
@ -756,31 +778,32 @@ void Fl_Xlib_Graphics_Driver::draw(const char *str, int n, int x, int y) {
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);
if (!(region && XEmptyRegion(region))) {
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+offset_x_, y+offset_y_, (XftChar16 *)buffer, n);
XftDrawString16(draw_, &color, font_descriptor()->font, x+offset_x_*scale_+line_delta_, y+offset_y_*scale_+line_delta_, (XftChar16 *)buffer, n);
#else
XftDrawString32(draw_, &color, font_descriptor()->font, x+offset_x_, y+offset_y_, (XftChar32 *)buffer, n);
XftDrawString32(draw_, &color, font_descriptor()->font, x+offset_x_*scale_+line_delta_, y+offset_y_*scale_+line_delta_, (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);
void Fl_Xlib_Graphics_Driver::draw_unscaled(int angle, const char *str, int n, int x, int y) {
fl_xft_font(this, this->Fl_Graphics_Driver::font(), this->size_unscaled(), angle);
this->draw_unscaled(str, n, x, y);
fl_xft_font(this, this->Fl_Graphics_Driver::font(), this->size_unscaled(), 0);
}
void Fl_Xlib_Graphics_Driver::drawUCS4(const void *str, int n, int x, int y) {
@ -814,11 +837,11 @@ void Fl_Xlib_Graphics_Driver::drawUCS4(const void *str, int n, int x, int y) {
color.color.blue = ((int)b)*0x101;
color.color.alpha = 0xffff;
XftDrawString32(draw_, &color, font_descriptor()->font, x+offset_x_, y+offset_x_, (FcChar32 *)str, n);
XftDrawString32(draw_, &color, font_descriptor()->font, x+offset_x_*scale_+line_delta_, y+offset_y_*scale_+line_delta_, (FcChar32 *)str, n);
}
void Fl_Xlib_Graphics_Driver::rtl_draw(const char* c, int n, int x, int y) {
void Fl_Xlib_Graphics_Driver::rtl_draw_unscaled(const char* c, int n, int x, int y) {
#if defined(__GNUC__)
// FIXME: warning Need to improve this XFT right to left draw function
@ -902,7 +925,7 @@ int Fl_Xlib_Graphics_Driver::get_font_sizes(Fl_Font fnum, int*& sizep) {
float Fl_Xlib_Graphics_Driver::scale_font_for_PostScript(Fl_Font_Descriptor *desc, int s) {
// Xft font height is sometimes larger than the required size (see STR 2566).
// Increase the PostScript font size by 15% without exceeding the display font height
int max = height();
int max = height_unscaled();
float ps_size = s * 1.15;
if (ps_size > max) ps_size = max;
return ps_size;
@ -972,7 +995,7 @@ static void fl_xft_font(Fl_Xlib_Graphics_Driver *driver, Fl_Font fnum, Fl_Fontsi
return;
}
Fl_Font_Descriptor* f = driver->font_descriptor();
if (fnum == driver->Fl_Graphics_Driver::font() && size == driver->size() && f && f->angle == angle)
if (fnum == driver->Fl_Graphics_Driver::font() && size == driver->size_unscaled() && f && f->angle == angle)
return;
driver->Fl_Graphics_Driver::font(fnum, size);
Fl_Fontdesc *font = fl_fonts + fnum;
@ -1021,7 +1044,7 @@ static void fl_xft_font(Fl_Xlib_Graphics_Driver *driver, Fl_Font fnum, Fl_Fontsi
// 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 size = ((Fl_Xlib_Graphics_Driver*)driver)->size_unscaled();
int fnum = driver->font();
const char *wt_med = "medium";
const char *wt_bold = "bold";
@ -1112,10 +1135,10 @@ static XFontStruct* fl_xxfont(Fl_Graphics_Driver *driver) {
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())) {
if ((!xgl_font) || (glsize != ((Fl_Xlib_Graphics_Driver*)driver)->size_unscaled()) || (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
glsize = ((Fl_Xlib_Graphics_Driver*)driver)->size_unscaled(); // record current font size
glfont = driver->font(); // and face
xgl_font = load_xfont_for_xft2(driver);
}
@ -1126,7 +1149,7 @@ static XFontStruct* fl_xxfont(Fl_Graphics_Driver *driver) {
}
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.
xftfont = fontopen(fl_fonts[driver->font()].name, ((Fl_Xlib_Graphics_Driver*)driver)->size_unscaled(), true, 0); // else request XFT to load a suitable "core" font instead.
return xftfont->u.core.font;
# endif // XFT_MAJOR > 1
}
@ -1161,9 +1184,13 @@ PangoContext *Fl_Xlib_Graphics_Driver::context() {
return pctxt_;
}
void Fl_Xlib_Graphics_Driver::font(Fl_Font fnum, Fl_Fontsize size) {
void Fl_Xlib_Graphics_Driver::font_unscaled(Fl_Font fnum, Fl_Fontsize size) {
if (!size) return;
if (this->Fl_Graphics_Driver::font() == fnum && this->size() == size) return;
if (size < 0) {
Fl_Graphics_Driver::font(0, 0);
return;
}
if (this->Fl_Graphics_Driver::font() == fnum && this->size_unscaled() == size) return;
fl_xft_font(this, fnum, size, 0);
init_built_in_fonts();
if (pfd_) pango_font_description_free(pfd_);
@ -1180,21 +1207,21 @@ void Fl_Xlib_Graphics_Driver::font(Fl_Font fnum, Fl_Fontsize size) {
}
}
void Fl_Xlib_Graphics_Driver::draw(const char *str, int n, int x, int y) {
do_draw(0, str, n, x+offset_x_, y+offset_y_);
void Fl_Xlib_Graphics_Driver::draw_unscaled(const char *str, int n, int x, int y) {
do_draw(0, str, n, x+offset_x_*scale_, y+offset_y_*scale_);
}
void Fl_Xlib_Graphics_Driver::draw(int angle, const char *str, int n, int x, int y) {
void Fl_Xlib_Graphics_Driver::draw_unscaled(int angle, const char *str, int n, int x, int y) {
PangoMatrix mat = PANGO_MATRIX_INIT; // 1.6
pango_matrix_translate(&mat, x+offset_x_, y+offset_y_); // 1.6
pango_matrix_translate(&mat, x+offset_x_*scale_, y+offset_y_*scale_); // 1.6
pango_matrix_rotate(&mat, angle); // 1.6
pango_context_set_matrix(pctxt_, &mat); // 1.6
do_draw(0, str, n, 0, 0);
pango_context_set_matrix(pctxt_, NULL); // 1.6
}
void Fl_Xlib_Graphics_Driver::rtl_draw(const char* str, int n, int x, int y) {
do_draw(1, str, n, x+offset_x_, y+offset_y_);
void Fl_Xlib_Graphics_Driver::rtl_draw_unscaled(const char* str, int n, int x, int y) {
do_draw(1, str, n, x+offset_x_*scale_, y+offset_y_*scale_);
}
void Fl_Xlib_Graphics_Driver::do_draw(int from_right, const char *str, int n, int x, int y) {
@ -1245,12 +1272,13 @@ void Fl_Xlib_Graphics_Driver::do_draw(int from_right, const char *str, int n, in
else
XftDrawChange(draw_, draw_window = fl_window);
XftDrawSetClip(draw_, region);
pango_xft_render_layout(draw_, &color, playout_, x*PANGO_SCALE, (y-height()+descent())*PANGO_SCALE ); // 1.8
}
pango_xft_render_layout(draw_, &color, playout_, (x + line_delta_)*PANGO_SCALE,
(y+line_delta_-height_unscaled()+descent_unscaled())*PANGO_SCALE ); // 1.8
}
double Fl_Xlib_Graphics_Driver::width(const char* str, int n) {
double Fl_Xlib_Graphics_Driver::width_unscaled(const char* str, int n) {
if (!n) return 0;
if (!fl_display || fl_size() == 0) return -1;
if (!fl_display || size_ == 0) return -1;
if (!playout_) context();
int width, height;
pango_layout_set_font_description(playout_, pfd_);
@ -1259,30 +1287,31 @@ double Fl_Xlib_Graphics_Driver::width(const char* str, int n) {
return (double)width;
}
void Fl_Xlib_Graphics_Driver::text_extents(const char *str, int n, int &dx, int &dy, int &w, int &h) {
void Fl_Xlib_Graphics_Driver::text_extents_unscaled(const char *str, int n, int &dx, int &dy, int &w, int &h) {
if (!playout_) context();
pango_layout_set_font_description(playout_, pfd_);
pango_layout_set_text(playout_, str, n);
PangoRectangle ink_rect, logical_rect;
pango_layout_get_pixel_extents(playout_, &ink_rect, &logical_rect);
dx = ink_rect.x;
dy = ink_rect.y - height() + descent();
dx = ink_rect.x + line_delta_;
dy = ink_rect.y + line_delta_ - height_unscaled() + descent_unscaled();
w = ink_rect.width;
h = ink_rect.height;
correct_extents(scale_, dx, dy, w, h);
}
int Fl_Xlib_Graphics_Driver::height() {
int Fl_Xlib_Graphics_Driver::height_unscaled() {
if (font_descriptor()) return font_descriptor()->height_;
else return -1;
}
double Fl_Xlib_Graphics_Driver::width(unsigned int c) {
double Fl_Xlib_Graphics_Driver::width_unscaled(unsigned int c) {
char buf4[4];
int n = fl_utf8encode(c, buf4);
return width(buf4, n);
return width_unscaled(buf4, n);
}
int Fl_Xlib_Graphics_Driver::descent() {
int Fl_Xlib_Graphics_Driver::descent_unscaled() {
if (font_descriptor()) return font_descriptor()->descent_;
else return -1;
}

View File

@ -47,10 +47,13 @@
#include <config.h>
#include "Fl_Xlib_Graphics_Driver.H"
#include "../X11/Fl_X11_Screen_Driver.H"
#include "../X11/Fl_X11_Window_Driver.H"
# include <FL/Fl.H>
# include <FL/fl_draw.H>
# include <FL/x.H>
# include <FL/Fl_Image_Surface.H>
# include <FL/Fl_Screen_Driver.H>
# include "../../Fl_XColor.H"
# include "../../flstring.h"
#if HAVE_XRENDER
@ -476,7 +479,6 @@ static void innards(const uchar *buf, int X, int Y, int W, int H,
if (w<=0 || h<=0) return;
dx -= X;
dy -= Y;
if (!bytes_per_pixel) figure_out_visual();
const unsigned oldbpp = bytes_per_pixel;
static GC gc32 = None;
@ -574,32 +576,32 @@ static void innards(const uchar *buf, int X, int Y, int W, int H,
}
}
void Fl_Xlib_Graphics_Driver::draw_image(const uchar* buf, int x, int y, int w, int h, int d, int l){
void Fl_Xlib_Graphics_Driver::draw_image_unscaled(const uchar* buf, int x, int y, int w, int h, int d, int l){
const bool alpha = !!(abs(d) & FL_IMAGE_WITH_ALPHA);
if (alpha) d ^= FL_IMAGE_WITH_ALPHA;
const int mono = (d>-3 && d<3);
innards(buf,x+offset_x_,y+offset_y_,w,h,d,l,mono,0,0,alpha,gc_);
innards(buf,x+offset_x_*scale_,y+offset_y_*scale_,w,h,d,l,mono,0,0,alpha,gc_);
}
void Fl_Xlib_Graphics_Driver::draw_image(Fl_Draw_Image_Cb cb, void* data,
void Fl_Xlib_Graphics_Driver::draw_image_unscaled(Fl_Draw_Image_Cb cb, void* data,
int x, int y, int w, int h,int d) {
const bool alpha = !!(abs(d) & FL_IMAGE_WITH_ALPHA);
if (alpha) d ^= FL_IMAGE_WITH_ALPHA;
const int mono = (d>-3 && d<3);
innards(0,x+offset_x_,y+offset_y_,w,h,d,0,mono,cb,data,alpha,gc_);
innards(0,x+offset_x_*scale_,y+offset_y_*scale_,w,h,d,0,mono,cb,data,alpha,gc_);
}
void Fl_Xlib_Graphics_Driver::draw_image_mono(const uchar* buf, int x, int y, int w, int h, int d, int l){
innards(buf,x+offset_x_,y+offset_y_,w,h,d,l,1,0,0,0,gc_);
void Fl_Xlib_Graphics_Driver::draw_image_mono_unscaled(const uchar* buf, int x, int y, int w, int h, int d, int l){
innards(buf,x+offset_x_*scale_,y+offset_y_*scale_,w,h,d,l,1,0,0,0,gc_);
}
void Fl_Xlib_Graphics_Driver::draw_image_mono(Fl_Draw_Image_Cb cb, void* data,
void Fl_Xlib_Graphics_Driver::draw_image_mono_unscaled(Fl_Draw_Image_Cb cb, void* data,
int x, int y, int w, int h,int d) {
innards(0,x+offset_x_,y+offset_y_,w,h,d,0,1,cb,data,0,gc_);
innards(0,x+offset_x_*scale_,y+offset_y_*scale_,w,h,d,0,1,cb,data,0,gc_);
}
void fl_rectf(int x, int y, int w, int h, uchar r, uchar g, uchar b) {
@ -622,15 +624,14 @@ void Fl_Xlib_Graphics_Driver::delete_bitmask(Fl_Bitmask bm) {
XFreePixmap(fl_display, bm);
}
void Fl_Xlib_Graphics_Driver::draw(Fl_Bitmap *bm, int XP, int YP, int WP, int HP, int cx, int cy) {
int X, Y, W, H;
if (Fl_Graphics_Driver::prepare(bm, XP+offset_x_, YP+offset_y_, WP, HP, cx, cy, X, Y, W, H)) {
return;
}
void Fl_Xlib_Graphics_Driver::draw_unscaled(Fl_Bitmap *bm, float s, int X, int Y, int W, int H, int cx, int cy) {
X = (X+offset_x_)*s;
Y = (Y+offset_y_)*s;
cache_size(bm, W, H);
cx *= s; cy *= s;
XSetStipple(fl_display, gc_, *Fl_Graphics_Driver::id(bm));
int ox = X-cx; if (ox < 0) ox += bm->w();
int oy = Y-cy; if (oy < 0) oy += bm->h();
int ox = X-cx; if (ox < 0) ox += bm->w()*s;
int oy = Y-cy; if (oy < 0) oy += bm->h()*s;
XSetTSOrigin(fl_display, gc_, ox, oy);
XSetFillStyle(fl_display, gc_, FillStippled);
XFillRectangle(fl_display, fl_window, gc_, X, Y, W, H);
@ -715,33 +716,42 @@ static Fl_Offscreen cache_rgb(Fl_RGB_Image *img) {
return off;
}
void Fl_Xlib_Graphics_Driver::draw(Fl_RGB_Image *img, int XP, int YP, int WP, int HP, int cx, int cy) {
int X, Y, W, H;
XP += offset_x_;
YP += offset_y_;
// Don't draw an empty image...
if (!img->d() || !img->array) {
Fl_Graphics_Driver::draw_empty(img, XP, YP);
return;
}
if (start_image(img, XP, YP, WP, HP, cx, cy, X, Y, W, H)) {
return;
}
// X,Y,W,H,cx,cy are in FLTK units
// if s != 1 and id(img) != 0, the offscreen has been previously scaled by s
// if s != 1 and id(img) == 0, img has been previously scaled by s
void Fl_Xlib_Graphics_Driver::draw_unscaled(Fl_RGB_Image *img, float s, int X, int Y, int W, int H, int cx, int cy) {
X = (X+offset_x_)*s;
Y = (Y+offset_y_)*s;
cache_size(img, W, H);
cx *= s; cy *= s;
if (!*Fl_Graphics_Driver::id(img)) {
*Fl_Graphics_Driver::id(img) = cache_rgb(img);
*cache_scale(img) = 1;
}
Fl_Region r2 = scale_clip(s);
if (*Fl_Graphics_Driver::id(img)) {
if (img->d() == 4 || img->d() == 2) {
#if HAVE_XRENDER
scale_and_render_pixmap(*Fl_Graphics_Driver::id(img), 4, 1, 1, cx, cy, X - offset_x_, Y - offset_y_, W, H);
scale_and_render_pixmap(*Fl_Graphics_Driver::id(img), img->d(), 1, 1, cx, cy, X, Y, W, H);
#endif
} else {
copy_offscreen(X - offset_x_, Y - offset_y_, W, H, *Fl_Graphics_Driver::id(img), cx, cy);
XCopyArea(fl_display, *Fl_Graphics_Driver::id(img), fl_window, gc_, cx, cy, W, H, X, Y);
}
} else {
// Composite image with alpha manually each time...
scale_ = 1;
int ox = offset_x_, oy = offset_y_;
offset_x_ = offset_y_ = 0;
Fl_X11_Screen_Driver *d = (Fl_X11_Screen_Driver*)Fl::screen_driver();
int nscreen = Fl_Window::current()->driver()->screen_num();
float keep = d->scale(nscreen);
d->scale(nscreen, 1);
alpha_blend(img, X, Y, W, H, cx, cy);
d->scale(nscreen, keep);
scale_ = s;
offset_x_ = ox; offset_y_ = oy;
}
unscale_clip(r2);
}
void Fl_Xlib_Graphics_Driver::uncache(Fl_RGB_Image*, fl_uintptr_t &id_, fl_uintptr_t &mask_)
@ -752,13 +762,17 @@ void Fl_Xlib_Graphics_Driver::uncache(Fl_RGB_Image*, fl_uintptr_t &id_, fl_uintp
}
}
fl_uintptr_t Fl_Xlib_Graphics_Driver::cache(Fl_Bitmap*, int w, int h, const uchar *array) {
fl_uintptr_t Fl_Xlib_Graphics_Driver::cache(Fl_Bitmap *bm, int w, int h, const uchar *array) {
*cache_scale(bm) = Fl_Scalable_Graphics_Driver::scale();
return (fl_uintptr_t)create_bitmask(w, h, array);
}
void Fl_Xlib_Graphics_Driver::draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) {
int X, Y, W, H;
if (Fl_Graphics_Driver::prepare(pxm, XP+offset_x_, YP+offset_y_, WP, HP, cx, cy, X, Y, W, H)) return;
void Fl_Xlib_Graphics_Driver::draw_unscaled(Fl_Pixmap *pxm, float s, int X, int Y, int W, int H, int cx, int cy) {
X = (X+offset_x_)*s;
Y = (Y+offset_y_)*s;
cache_size(pxm, W, H);
cx *= s; cy *= s;
Fl_Region r2 = scale_clip(s);
if (*Fl_Graphics_Driver::mask(pxm)) {
// make X use the bitmap as a mask:
XSetClipMask(fl_display, gc_, *Fl_Graphics_Driver::mask(pxm));
@ -781,21 +795,24 @@ void Fl_Xlib_Graphics_Driver::draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int H
Y1 = r->rects[i].y1;
W1 = r->rects[i].x2 - r->rects[i].x1;
H1 = r->rects[i].y2 - r->rects[i].y1;
copy_offscreen(X1-offset_x_, Y1-offset_y_, W1, H1, *Fl_Graphics_Driver::id(pxm), cx + (X1 - X), cy + (Y1 - Y));
XCopyArea(fl_display, *Fl_Graphics_Driver::id(pxm), fl_window, gc_, cx + (X1 - X), cy + (Y1 - Y), W1, H1, X1, Y1);
}
XDestroyRegion(r);
} else {
copy_offscreen(X-offset_x_, Y-offset_y_, W, H, *Fl_Graphics_Driver::id(pxm), cx, cy);
XCopyArea(fl_display, *Fl_Graphics_Driver::id(pxm), fl_window, gc_, cx, cy, W, H, X, Y);
}
// put the old clip region back
XSetClipOrigin(fl_display, gc_, 0, 0);
s = scale_; scale_ = 1;
restore_clip();
scale_ = s;
}
else copy_offscreen(X-offset_x_, Y-offset_y_, W, H, *Fl_Graphics_Driver::id(pxm), cx, cy);
else XCopyArea(fl_display, *Fl_Graphics_Driver::id(pxm), fl_window, gc_, cx, cy, W, H, X, Y);
unscale_clip(r2);
}
fl_uintptr_t Fl_Xlib_Graphics_Driver::cache(Fl_Pixmap *img, int w, int h, const char *const*data) {
fl_uintptr_t Fl_Xlib_Graphics_Driver::cache(Fl_Pixmap *pxm, int w, int h, const char *const*data) {
Fl_Offscreen id;
id = fl_create_offscreen(w, h);
fl_begin_offscreen(id);
@ -804,22 +821,26 @@ fl_uintptr_t Fl_Xlib_Graphics_Driver::cache(Fl_Pixmap *img, int w, int h, const
fl_draw_pixmap(data, 0, 0, FL_BLACK);
Fl_Surface_Device::surface()->driver()->mask_bitmap(0);
if (bitmap) {
*Fl_Graphics_Driver::mask(img) = (fl_uintptr_t)fl_create_bitmask(w, h, bitmap);
*Fl_Graphics_Driver::mask(pxm) = (fl_uintptr_t)create_bitmask(w * scale_, h * scale_, bitmap);
delete[] bitmap;
}
fl_end_offscreen();
*cache_scale(pxm) = Fl_Scalable_Graphics_Driver::scale();
return (fl_uintptr_t)id;
}
#if HAVE_XRENDER
/* Draws with Xrender an Fl_Offscreen with optional scaling and accounting for transparency if necessary.
XP,YP,WP,HP are in drawing units
*/
int Fl_Xlib_Graphics_Driver::scale_and_render_pixmap(Fl_Offscreen pixmap, int depth, double scale_x, double scale_y, int srcx, int srcy, int XP, int YP, int WP, int HP) {
bool has_alpha = (depth == 2 || depth == 4);
XRenderPictureAttributes srcattr;
memset(&srcattr, 0, sizeof(XRenderPictureAttributes));
static XRenderPictFormat *fmt32 = XRenderFindStandardFormat(fl_display, PictStandardARGB32);
static XRenderPictFormat *fmt24 = XRenderFindStandardFormat(fl_display, PictStandardRGB24);
Picture src = XRenderCreatePicture(fl_display, pixmap,
depth%2 == 0 ?fmt32:fmt24, 0, &srcattr);
Picture src = XRenderCreatePicture(fl_display, pixmap, has_alpha ?fmt32:fmt24, 0, &srcattr);
Picture dst = XRenderCreatePicture(fl_display, fl_window, fmt24, 0, &srcattr);
if (!src || !dst) {
fprintf(stderr, "Failed to create Render pictures (%lu %lu)\n", src, dst);
@ -836,22 +857,24 @@ int Fl_Xlib_Graphics_Driver::scale_and_render_pixmap(Fl_Offscreen pixmap, int de
}};
XRenderSetPictureTransform(fl_display, src, &mat);
}
XRenderComposite(fl_display, (depth%2 == 0 ? PictOpOver : PictOpSrc), src, None, dst, srcx, srcy, 0, 0,
XP + offset_x_, YP + offset_y_, WP, HP);
XRenderComposite(fl_display, (has_alpha ? PictOpOver : PictOpSrc), src, None, dst, srcx, srcy, 0, 0,
XP, YP, WP, HP);
XRenderFreePicture(fl_display, src);
XRenderFreePicture(fl_display, dst);
return 1;
}
// XP,YP,WP,HP are in FLTK units
int Fl_Xlib_Graphics_Driver::draw_scaled(Fl_Image *img, int XP, int YP, int WP, int HP) {
Fl_RGB_Image *rgb = img->as_rgb_image();
if (!rgb || !can_do_alpha_blending()) return 0;
if (!*Fl_Graphics_Driver::id(rgb)) {
*Fl_Graphics_Driver::id(rgb) = cache_rgb(rgb);
*cache_scale(rgb) = 1;
}
return scale_and_render_pixmap(*Fl_Graphics_Driver::id(rgb), rgb->d(), rgb->w()/double(WP), rgb->h()/double(HP),
0, 0, XP, YP, WP, HP);
cache_size(img, WP, HP);
return scale_and_render_pixmap( *Fl_Graphics_Driver::id(rgb), rgb->d(),
rgb->w() / double(WP), rgb->h() / double(HP), 0, 0, (XP + offset_x_)*scale_, (YP + offset_y_)*scale_, WP, HP);
}
#endif // HAVE_XRENDER

View File

@ -3,7 +3,7 @@
//
// Line style code for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2016 by Bill Spitzak and others.
// Copyright 1998-2017 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
@ -34,10 +34,9 @@
#include "Fl_Xlib_Graphics_Driver.H"
void Fl_Xlib_Graphics_Driver::line_style(int style, int width, char* dashes) {
void Fl_Xlib_Graphics_Driver::line_style_unscaled(int style, float width, char* dashes) {
// save line width for X11 clipping
if (width == 0) line_width_ = 1;
if (width == 0) line_width_ = scale_ < 2 ? 0 : scale_;
else line_width_ = width>0 ? width : -width;
int ndashes = dashes ? strlen(dashes) : 0;
@ -63,10 +62,12 @@ void Fl_Xlib_Graphics_Driver::line_style(int style, int width, char* dashes) {
case FL_DASHDOTDOT: *p++ = dash; *p++ = gap; *p++ = dot; *p++ = gap; *p++ = dot; *p++ = gap; break;
}
ndashes = p-buf;
if (*dashes == 0) ndashes = 0;//against error with very small scaling
}
static int Cap[4] = {CapButt, CapButt, CapRound, CapProjecting};
static int Join[4] = {JoinMiter, JoinMiter, JoinRound, JoinBevel};
XSetLineAttributes(fl_display, gc_, width,
XSetLineAttributes(fl_display, gc_,
line_width_,
ndashes ? LineOnOffDash : LineSolid,
Cap[(style>>8)&3], Join[(style>>12)&3]);
if (ndashes) XSetDashes(fl_display, gc_, 0, dashes, ndashes);

View File

@ -3,7 +3,7 @@
//
// Rectangle drawing routines for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2016 by Bill Spitzak and others.
// Copyright 1998-2017 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
@ -161,112 +161,167 @@ void Fl_Xlib_Graphics_Driver::XDestroyRegion(Fl_Region r) {
::XDestroyRegion(r);
}
// --- line and polygon drawing with integer coordinates
// --- line and polygon drawing
void Fl_Xlib_Graphics_Driver::point(int x, int y) {
XDrawPoint(fl_display, fl_window, gc_, clip_x(x+offset_x_), clip_x(y+offset_y_));
}
void Fl_Xlib_Graphics_Driver::rect(int x, int y, int w, int h) {
if (w<=0 || h<=0) return;
x+=offset_x_; y+=offset_y_;
void Fl_Xlib_Graphics_Driver::rect_unscaled(float fx, float fy, float fw, float fh) {
if (fw<=0 || fh<=0) return;
int deltaf = scale_ >= 2 ? scale_-1 : 0;
fx += offset_x_*scale_; fy += offset_y_*scale_;
int x = fx; int y = fy;
int w = int(int(fx/scale_+fw/scale_+0.5)*scale_) - x - 1 - deltaf;
int h = int(int(fy/scale_+fh/scale_+0.5)*scale_) - y - 1 - deltaf;
if (!clip_to_short(x, y, w, h, line_width_))
XDrawRectangle(fl_display, fl_window, gc_, x, y, w-1, h-1);
XDrawRectangle(fl_display, fl_window, gc_, x+line_delta_, y+line_delta_, w, h);
}
void Fl_Xlib_Graphics_Driver::rectf(int x, int y, int w, int h) {
if (w<=0 || h<=0) return;
x+=offset_x_; y+=offset_y_;
void Fl_Xlib_Graphics_Driver::rectf_unscaled(float fx, float fy, float fw, float fh) {
if (fw<=0 || fh<=0) return;
int deltaf = scale_ >= 2 ? scale_/2 : 0;
fx += offset_x_*scale_; fy += offset_y_*scale_;
int x = fx-deltaf; int y = fy-deltaf;
// make sure no unfilled area lies between rectf(x,y,w,h) and rectf(x+w,y,1,h) or rectf(x,y+w,w,1)
int w = int(int(fx/scale_+fw/scale_+0.5)*scale_) - int(fx);
int h = int(int(fy/scale_+fh/scale_+0.5)*scale_) - int(fy);
if (!clip_to_short(x, y, w, h, line_width_))
XFillRectangle(fl_display, fl_window, gc_, x, y, w, h);
XFillRectangle(fl_display, fl_window, gc_, x+line_delta_, y+line_delta_, w, h);
}
void Fl_Xlib_Graphics_Driver::line(int x, int y, int x1, int y1) {
XDrawLine(fl_display, fl_window, gc_, x+offset_x_, y+offset_y_, x1+offset_x_, y1+offset_y_);
void Fl_Xlib_Graphics_Driver::point_unscaled(float fx, float fy) {
int deltaf = scale_ >= 2 ? scale_/2 : 0;
int x = fx+offset_x_*scale_-deltaf; int y = fy+offset_y_*scale_-deltaf;
int width = scale_ >= 1 ? scale_ : 1;
XFillRectangle(fl_display, fl_window, gc_, x+line_delta_, y+line_delta_, width, width);
}
void Fl_Xlib_Graphics_Driver::line(int x, int y, int x1, int y1, int x2, int y2) {
void Fl_Xlib_Graphics_Driver::line_unscaled(float x, float y, float x1, float y1) {
if (x == x1) yxline_unscaled(x, y, y1);
else if (y == y1) xyline_unscaled(x, y, x1);
else XDrawLine(fl_display, fl_window, gc_, x+offset_x_*scale_+line_delta_, y+offset_y_*scale_+line_delta_, x1+offset_x_*scale_+line_delta_, y1+offset_y_*scale_+line_delta_);
}
void Fl_Xlib_Graphics_Driver::line_unscaled(float x, float y, float x1, float y1, float x2, float y2) {
XPoint p[3];
p[0].x = x+offset_x_; p[0].y = y+offset_y_;
p[1].x = x1+offset_x_; p[1].y = y1+offset_y_;
p[2].x = x2+offset_x_; p[2].y = y2+offset_y_;
p[0].x = x+offset_x_*scale_+line_delta_; p[0].y = y+offset_y_*scale_+line_delta_;
p[1].x = x1+offset_x_*scale_+line_delta_; p[1].y = y1+offset_y_*scale_+line_delta_;
p[2].x = x2+offset_x_*scale_+line_delta_; p[2].y = y2+offset_y_*scale_+line_delta_;
XDrawLines(fl_display, fl_window, gc_, p, 3, 0);
}
void Fl_Xlib_Graphics_Driver::xyline(int x, int y, int x1) {
XDrawLine(fl_display, fl_window, gc_, clip_x(x+offset_x_), clip_x(y+offset_y_), clip_x(x1+offset_x_), clip_x(y+offset_y_));
void Fl_Xlib_Graphics_Driver::xyline_unscaled(float x, float y, float x1) {//OK
x+=offset_x_*scale_; y+=offset_y_*scale_; x1 += offset_x_*scale_;
int tw = line_width_ ? line_width_ : 1; // true line width
if (x > x1) { float exch = x; x = x1; x1 = exch; }
int ix = clip_x(x+line_delta_); if (scale_ >= 2) ix -= int(scale_/2);
int iy = clip_x(y+line_delta_);
int ix1 = int(x1/scale_+1.5)*scale_-1; if (scale_ >= 2) ix1 += int(scale_/2); if (scale_ >= 4) ix1 -= scale_/2;
XDrawLine(fl_display, fl_window, gc_, ix, iy, ix1, iy);
// try and make sure no unfilled area lies between xyline(x,y,x1) and xyline(x,y+1,x1)
if (y+line_delta_ + scale_ >= iy + tw+1 - 0.001 ) XDrawLine(fl_display, fl_window, gc_, ix, iy+1, ix1, iy+1);
}
void Fl_Xlib_Graphics_Driver::xyline(int x, int y, int x1, int y2) {
void Fl_Xlib_Graphics_Driver::xyline_unscaled(float x, float y, float x1, float y2) {//OK
x+=offset_x_*scale_; y+=offset_y_*scale_; x1 += offset_x_*scale_; y2+=offset_y_*scale_;
if (scale_ >= 2) {
int delta = int(scale_/2 + 0.5);
if (x > x1) x += delta; else x -= delta;
if (y2 > y) y2 += delta; else y2 -= delta;
}
XPoint p[3];
p[0].x = clip_x(x+offset_x_); p[0].y = p[1].y = clip_x(y+offset_y_);
p[1].x = p[2].x = clip_x(x1+offset_x_); p[2].y = clip_x(y2+offset_y_);
p[0].x = clip_x(x+line_delta_); p[0].y = p[1].y = clip_x(y+line_delta_);
p[1].x = p[2].x = clip_x(x1+line_delta_); p[2].y = clip_x(y2+line_delta_);
XDrawLines(fl_display, fl_window, gc_, p, 3, 0);
}
void Fl_Xlib_Graphics_Driver::xyline(int x, int y, int x1, int y2, int x3) {
void Fl_Xlib_Graphics_Driver::xyline_unscaled(float x, float y, float x1, float y2, float x3) {
x+=offset_x_*scale_; y+=offset_y_*scale_; x1 += offset_x_*scale_; y2+=offset_y_*scale_; x3 += offset_x_*scale_;
if (scale_ >= 2) {
int delta = int(scale_/2 + 0.5);
if (x > x1) x += delta; else x -= delta;
if (x3 > x1) x3 += delta; else x3 -= delta;
}
XPoint p[4];
p[0].x = clip_x(x+offset_x_); p[0].y = p[1].y = clip_x(y+offset_y_);
p[1].x = p[2].x = clip_x(x1+offset_x_); p[2].y = p[3].y = clip_x(y2+offset_y_);
p[3].x = clip_x(x3+offset_x_);
p[0].x = clip_x(x+line_delta_); p[0].y = p[1].y = clip_x(y+line_delta_);
p[1].x = p[2].x = clip_x(x1+line_delta_); p[2].y = p[3].y = clip_x(y2+line_delta_);
p[3].x = clip_x(x3+line_delta_);
XDrawLines(fl_display, fl_window, gc_, p, 4, 0);
}
void Fl_Xlib_Graphics_Driver::yxline(int x, int y, int y1) {
XDrawLine(fl_display, fl_window, gc_, clip_x(x+offset_x_), clip_x(y+offset_y_), clip_x(x+offset_x_), clip_x(y1+offset_y_));
void Fl_Xlib_Graphics_Driver::yxline_unscaled(float x, float y, float y1) {//OK
x+=offset_x_*scale_; y+=offset_y_*scale_; y1 += offset_y_*scale_;
int tw = line_width_ ? line_width_ : 1; // true line width
if (y > y1) { float exch = y; y = y1; y1 = exch; }
int ix = clip_x(x+line_delta_);
int iy = clip_x(y+line_delta_); if (scale_ >= 2) iy -= int(scale_/2);
int iy1 = int(y1/scale_+1.5)*scale_-1; if (scale_ >= 2) iy1 += int(scale_/2); if (scale_ >= 4) iy1 -= scale_/2;
XDrawLine(fl_display, fl_window, gc_, ix, iy, ix, iy1);
// try and make sure no unfilled area lies between yxline(x,y,y1) and yxline(x+1,y,y1)
if (x+line_delta_+scale_ >= ix + tw+1 -0.001) XDrawLine(fl_display, fl_window, gc_, ix+1, iy, ix+1, iy1);
}
void Fl_Xlib_Graphics_Driver::yxline(int x, int y, int y1, int x2) {
void Fl_Xlib_Graphics_Driver::yxline_unscaled(float x, float y, float y1, float x2) {
x+=offset_x_*scale_; y+=offset_y_*scale_; y1 += offset_y_*scale_; x2+=offset_x_*scale_;
if (scale_ >= 2) {
int delta = int(scale_/2 + 0.5);
if (y > y1) y += delta; else y -= delta;
if (x2 > x) x2 += delta; else x2 -= delta;
}
XPoint p[3];
p[0].x = p[1].x = clip_x(x+offset_x_); p[0].y = clip_x(y+offset_y_);
p[1].y = p[2].y = clip_x(y1+offset_y_); p[2].x = clip_x(x2+offset_x_);
p[0].x = p[1].x = clip_x(x+line_delta_); p[0].y = clip_x(y+line_delta_);
p[1].y = p[2].y = clip_x(y1+line_delta_); p[2].x = clip_x(x2+line_delta_);
XDrawLines(fl_display, fl_window, gc_, p, 3, 0);
}
void Fl_Xlib_Graphics_Driver::yxline(int x, int y, int y1, int x2, int y3) {
void Fl_Xlib_Graphics_Driver::yxline_unscaled(float x, float y, float y1, float x2, float y3) {
x+=offset_x_*scale_; y+=offset_y_*scale_; y1 += offset_y_*scale_; x2+=offset_x_*scale_; y3 += offset_y_*scale_;
if (scale_ >= 2) {
int delta = int(scale_/2 + 0.5);
if (y > y1) y += delta; else y -= delta;
if (y3 > y1) y3 += delta; else y3 -= delta;
}
XPoint p[4];
p[0].x = p[1].x = clip_x(x+offset_x_); p[0].y = clip_x(y+offset_y_);
p[1].y = p[2].y = clip_x(y1+offset_y_); p[2].x = p[3].x = clip_x(x2+offset_x_);
p[3].y = clip_x(y3+offset_y_);
p[0].x = p[1].x = clip_x(x+line_delta_); p[0].y = clip_x(y+line_delta_);
p[1].y = p[2].y = clip_x(y1+line_delta_); p[2].x = p[3].x = clip_x(x2+line_delta_);
p[3].y = clip_x(y3+line_delta_);
XDrawLines(fl_display, fl_window, gc_, p, 4, 0);
}
void Fl_Xlib_Graphics_Driver::loop(int x, int y, int x1, int y1, int x2, int y2) {
void Fl_Xlib_Graphics_Driver::loop_unscaled(float x, float y, float x1, float y1, float x2, float y2) {
XPoint p[4];
p[0].x = x+offset_x_; p[0].y = y+offset_y_;
p[1].x = x1+offset_x_; p[1].y = y1+offset_y_;
p[2].x = x2+offset_x_; p[2].y = y2+offset_y_;
p[3].x = x+offset_x_; p[3].y = y+offset_y_;
p[0].x = x +offset_x_*scale_+line_delta_; p[0].y = y +offset_y_*scale_+line_delta_;
p[1].x = x1 +offset_x_*scale_+line_delta_; p[1].y = y1 +offset_y_*scale_+line_delta_;
p[2].x = x2 +offset_x_*scale_+line_delta_; p[2].y = y2 +offset_y_*scale_+line_delta_;
p[3].x = x +offset_x_*scale_+line_delta_; p[3].y = y +offset_y_*scale_+line_delta_;
XDrawLines(fl_display, fl_window, 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) {
void Fl_Xlib_Graphics_Driver::loop_unscaled(float x, float y, float x1, float y1, float x2, float y2, float x3, float y3) {
XPoint p[5];
p[0].x = x+offset_x_; p[0].y = y+offset_y_;
p[1].x = x1+offset_x_; p[1].y = y1+offset_y_;
p[2].x = x2+offset_x_; p[2].y = y2+offset_y_;
p[3].x = x3+offset_x_; p[3].y = y3+offset_y_;
p[4].x = x+offset_x_; p[4].y = y+offset_y_;
p[0].x = x+offset_x_*scale_+line_delta_; p[0].y = y+offset_y_*scale_+line_delta_;
p[1].x = x1 +offset_x_*scale_+line_delta_; p[1].y = y1+offset_y_*scale_+line_delta_;
p[2].x = x2+offset_x_*scale_+line_delta_; p[2].y = y2+offset_y_*scale_+line_delta_;
p[3].x = x3+offset_x_*scale_+line_delta_; p[3].y = y3+offset_y_*scale_+line_delta_;
p[4].x = x+offset_x_*scale_+line_delta_; p[4].y = y+offset_y_*scale_+line_delta_;
XDrawLines(fl_display, fl_window, gc_, p, 5, 0);
}
void Fl_Xlib_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int y2) {
void Fl_Xlib_Graphics_Driver::polygon_unscaled(float x, float y, float x1, float y1, float x2, float y2) {
XPoint p[4];
p[0].x = x+offset_x_; p[0].y = y+offset_y_;
p[1].x = x1+offset_x_; p[1].y = y1+offset_y_;
p[2].x = x2+offset_x_; p[2].y = y2+offset_y_;
p[3].x = x+offset_x_; p[3].y = y+offset_y_;
p[0].x = x+offset_x_*scale_+line_delta_; p[0].y = y+offset_y_*scale_+line_delta_;
p[1].x = x1+offset_x_*scale_+line_delta_; p[1].y = y1+offset_y_*scale_+line_delta_;
p[2].x = x2+offset_x_*scale_+line_delta_; p[2].y = y2+offset_y_*scale_+line_delta_;
p[3].x = x+offset_x_*scale_+line_delta_; p[3].y = y+offset_y_*scale_+line_delta_;
XFillPolygon(fl_display, fl_window, gc_, p, 3, Convex, 0);
XDrawLines(fl_display, fl_window, 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) {
void Fl_Xlib_Graphics_Driver::polygon_unscaled(float x, float y, float x1, float y1, float x2, float y2, float x3, float y3) {
XPoint p[5];
p[0].x = x+offset_x_; p[0].y = y+offset_y_;
p[1].x = x1+offset_x_; p[1].y = y1+offset_y_;
p[2].x = x2+offset_x_; p[2].y = y2+offset_y_;
p[3].x = x3+offset_x_; p[3].y = y3+offset_y_;
p[4].x = x+offset_x_; p[4].y = y+offset_y_;
p[0].x = x+offset_x_*scale_+line_delta_; p[0].y = y+offset_y_*scale_+line_delta_;
p[1].x = x1+offset_x_*scale_+line_delta_; p[1].y = y1+offset_y_*scale_+line_delta_;
p[2].x = x2+offset_x_*scale_+line_delta_; p[2].y = y2+offset_y_*scale_+line_delta_;
p[3].x = x3+offset_x_*scale_+line_delta_; p[3].y = y3+offset_y_*scale_+line_delta_;
p[4].x = x+offset_x_*scale_+line_delta_; p[4].y = y+offset_y_*scale_+line_delta_;
XFillPolygon(fl_display, fl_window, gc_, p, 4, Convex, 0);
XDrawLines(fl_display, fl_window, gc_, p, 5, 0);
}
@ -276,7 +331,7 @@ void Fl_Xlib_Graphics_Driver::polygon(int x, int y, int x1, int y1, int x2, int
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+offset_x_,y+offset_y_,w,h);
r = XRectangleRegion(x,y,w,h);
Fl_Region current = rstack[rstackptr];
if (current) {
Fl_Region temp = XCreateRegion();
@ -294,8 +349,6 @@ void Fl_Xlib_Graphics_Driver::push_clip(int x, int y, int w, int h) {
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;
x += offset_x_;
y += offset_y_;
Fl_Region r = rstack[rstackptr];
if (!r) return 0;
switch (XRectInRegion(r, x, y, w, h)) {
@ -312,15 +365,13 @@ int Fl_Xlib_Graphics_Driver::clip_box(int x, int y, int w, int h, int& X, int& Y
XIntersectRegion(r, rr, temp);
XRectangle rect;
XClipBox(temp, &rect);
X = rect.x - offset_x_; Y = rect.y - offset_y_; W = rect.width; H = rect.height;
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) {
x += offset_x_;
y += offset_y_;
if (x+w <= 0 || y+h <= 0) return 0;
Fl_Region r = rstack[rstackptr];
if (!r) return 1;
@ -348,8 +399,12 @@ void Fl_Xlib_Graphics_Driver::pop_clip() {
void Fl_Xlib_Graphics_Driver::restore_clip() {
fl_clip_state_number++;
if (gc_) {
Fl_Region r = rstack[rstackptr];
if (r) XSetRegion(fl_display, gc_, r);
Region r = rstack[rstackptr];
if (r) {
Region r2 = scale_clip(scale_);
XSetRegion(fl_display, gc_, rstack[rstackptr]);
unscale_clip(r2);
}
else XSetClipMask(fl_display, gc_, 0);
}
}

View File

@ -3,7 +3,7 @@
//
// Portable drawing routines for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2016 by Bill Spitzak and others.
// Copyright 1998-2017 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
@ -30,14 +30,6 @@
#include <FL/math.h>
void Fl_Xlib_Graphics_Driver::transformed_vertex(double xf, double yf) {
transformed_vertex0(short(rint(xf)), short(rint(yf)));
}
void Fl_Xlib_Graphics_Driver::vertex(double x,double y) {
transformed_vertex0(short(x*m.a + y*m.c + m.x), short(x*m.b + y*m.d + m.y));
}
void Fl_Xlib_Graphics_Driver::end_points() {
if (n>1) XDrawPoints(fl_display, fl_window, gc_, (XPoint*)p, n, 0);
}
@ -52,7 +44,9 @@ void Fl_Xlib_Graphics_Driver::end_line() {
void Fl_Xlib_Graphics_Driver::end_loop() {
fixloop();
if (n>2) transformed_vertex((short)p[0].x, (short)p[0].y);
if (n>2) {
transformed_vertex0(p[0].x, p[0].y);
}
end_line();
}
@ -73,7 +67,7 @@ void Fl_Xlib_Graphics_Driver::begin_complex_polygon() {
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((short)p[gap_].x, (short)p[gap_].y);
transformed_vertex0(p[gap_].x, p[gap_].y);
gap_ = n;
} else {
n = gap_;
@ -92,12 +86,7 @@ void Fl_Xlib_Graphics_Driver::end_complex_polygon() {
// 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));
void Fl_Xlib_Graphics_Driver::ellipse_unscaled(double xt, double yt, double rx, double ry) {
int llx = (int)rint(xt-rx);
int w = (int)rint(xt+rx)-llx;
int lly = (int)rint(yt-ry);

View File

@ -24,12 +24,13 @@
#include "Fl_Xlib_Graphics_Driver.H"
#include <FL/Fl_Image_Surface.H>
#include "Fl_Xlib_Graphics_Driver.H"
#include <FL/Fl_Screen_Driver.H>
class Fl_Xlib_Image_Surface_Driver : public Fl_Image_Surface_Driver {
friend class Fl_Image_Surface;
virtual void end_current_(Fl_Surface_Device *next_current);
public:
Window pre_window;
int was_high;
Fl_Xlib_Image_Surface_Driver(int w, int h, int high_res, Fl_Offscreen off);
~Fl_Xlib_Image_Surface_Driver();
void set_current();
@ -44,11 +45,18 @@ Fl_Image_Surface_Driver *Fl_Image_Surface_Driver::newImageSurfaceDriver(int w, i
}
Fl_Xlib_Image_Surface_Driver::Fl_Xlib_Image_Surface_Driver(int w, int h, int high_res, Fl_Offscreen off) : Fl_Image_Surface_Driver(w, h, high_res, off) {
float d = 1;
if (!off) {
fl_open_display();
d = fl_graphics_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);
}
driver(new Fl_Xlib_Graphics_Driver());
if (d != 1 && high_res) ((Fl_Xlib_Graphics_Driver*)driver())->scale(d);
}
Fl_Xlib_Image_Surface_Driver::~Fl_Xlib_Image_Surface_Driver() {
@ -73,9 +81,7 @@ void Fl_Xlib_Image_Surface_Driver::untranslate() {
Fl_RGB_Image* Fl_Xlib_Image_Surface_Driver::image()
{
unsigned char *data = fl_read_image(NULL, 0, 0, width, height, 0);
Fl_RGB_Image *image = new Fl_RGB_Image(data, width, height);
image->alloc_array = 1;
Fl_RGB_Image *image = Fl::screen_driver()->read_win_rectangle(NULL, 0, 0, width, height, 0);
return image;
}

View File

@ -3,7 +3,7 @@
//
// Overlay support for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2016 by Bill Spitzak and others.
// Copyright 1998-2017 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
@ -36,6 +36,12 @@ static int px,py,pw,ph;
#ifndef USE_XOR
#include <stdlib.h>
static uchar *bgN = 0L, *bgS = 0L, *bgE = 0L, *bgW = 0L;
#include <FL/Fl_Screen_Driver.H>
#include <FL/Fl_RGB_Image.H>
#include <FL/Fl_Shared_Image.H>
static Fl_Shared_Image *s_bgN = 0, *s_bgS = 0, *s_bgE = 0, *s_bgW = 0;
static int bgx, bgy, bgw, bgh;
#endif
@ -60,24 +66,58 @@ static void draw_current_rect() {
# error unsupported platform
# endif
#else
if (bgN) { free(bgN); bgN = 0L; }
if (bgS) { free(bgS); bgS = 0L; }
if (bgE) { free(bgE); bgE = 0L; }
if (bgW) { free(bgW); bgW = 0L; }
float s = fl_graphics_driver->scale();
if (s == int(s)) {
if (bgN) { free(bgN); bgN = 0L; }
if (bgS) { free(bgS); bgS = 0L; }
if (bgE) { free(bgE); bgE = 0L; }
if (bgW) { free(bgW); bgW = 0L; }
} else {
if (s_bgN) { s_bgN->release(); s_bgN = 0; }
if (s_bgS) { s_bgS->release(); s_bgS = 0; }
if (s_bgE) { s_bgE->release(); s_bgE = 0; }
if (s_bgW) { s_bgW->release(); s_bgW = 0; }
}
if (pw>0 && ph>0) {
bgE = fl_read_image(0L, px+pw-1, py, 1, ph);
bgW = fl_read_image(0L, px, py, 1, ph);
bgS = fl_read_image(0L, px, py+ph-1, pw, 1);
bgN = fl_read_image(0L, px, py, pw, 1);
if (s == int(s)) {
bgE = fl_read_image(0L, px+pw-1, py, 1, ph);
bgW = fl_read_image(0L, px, py, 1, ph);
bgS = fl_read_image(0L, px, py+ph-1, pw, 1);
bgN = fl_read_image(0L, px, py, pw, 1);
} else {
Fl_RGB_Image *tmp;
tmp = Fl::screen_driver()->read_win_rectangle(NULL, px+pw-1, py, 1, ph, 0);
if(tmp && tmp->w() && tmp->h()) {
s_bgE = Fl_Shared_Image::get(tmp);
s_bgE->scale(1, ph,0,1);
}
tmp = Fl::screen_driver()->read_win_rectangle(NULL, px, py, 1, ph, 0);
if(tmp && tmp->w() && tmp->h()) {
s_bgW = Fl_Shared_Image::get(tmp);
s_bgW->scale(1, ph,0,1);
}
tmp = Fl::screen_driver()->read_win_rectangle(NULL, px, py+ph-1, pw, 1, 0);
if(tmp && tmp->w() && tmp->h()) {
s_bgS = Fl_Shared_Image::get(tmp);
s_bgS->scale(pw, 1,0,1);
}
tmp = Fl::screen_driver()->read_win_rectangle(NULL, px, py, pw, 1, 0);
if(tmp && tmp->w() && tmp->h()) {
s_bgN = Fl_Shared_Image::get(tmp);
s_bgN->scale(pw, 1,0,1);
}
}
bgx = px; bgy = py;
bgw = pw; bgh = ph;
}
fl_color(FL_WHITE);
fl_line_style(FL_SOLID);
fl_rect(px, py, pw, ph);
if (s == int(s)) fl_rect(px, py, pw, ph);
else fl_loop(px, py, px+pw-1, py, px+pw-1, py+ph-1, px, py+ph-1);
fl_color(FL_BLACK);
fl_line_style(FL_DOT);
fl_rect(px, py, pw, ph);
if (s == int(s)) fl_rect(px, py, pw, ph);
else fl_loop(px, py, px+pw-1, py, px+pw-1, py+ph-1, px, py+ph-1);
fl_line_style(FL_SOLID);
#endif // USE_XOR
}
@ -90,10 +130,18 @@ static void erase_current_rect() {
draw_current_rect();
# endif
#else
if (bgN) fl_draw_image(bgN, bgx, bgy, bgw, 1);
if (bgS) fl_draw_image(bgS, bgx, bgy+bgh-1, bgw, 1);
if (bgW) fl_draw_image(bgW, bgx, bgy, 1, bgh);
if (bgE) fl_draw_image(bgE, bgx+bgw-1, bgy, 1, bgh);
float s = fl_graphics_driver->scale();
if (s == int(s)) {
if (bgN) fl_draw_image(bgN, bgx, bgy, bgw, 1);
if (bgS) fl_draw_image(bgS, bgx, bgy+bgh-1, bgw, 1);
if (bgW) fl_draw_image(bgW, bgx, bgy, 1, bgh);
if (bgE) fl_draw_image(bgE, bgx+bgw-1, bgy, 1, bgh);
} else {
if (s_bgN) s_bgN->draw(bgx, bgy);
if (s_bgS) s_bgS->draw(bgx, (bgy+bgh-1));
if (s_bgW) s_bgW->draw(bgx, bgy);
if (s_bgE) s_bgE->draw((bgx+bgw-1), bgy);
}
#endif
}

View File

@ -3,7 +3,7 @@
//
// Portable drawing routines for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2011 by Bill Spitzak and others.
// Copyright 1998-2017 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
@ -78,16 +78,6 @@ void Fl_Graphics_Driver::rotate(double d) {
}
}
/** see fl_scale(double, double) */
void Fl_Graphics_Driver::scale(double x, double y) {
mult_matrix(x,0,0,y,0,0);
}
/** see fl_scale(double) */
void Fl_Graphics_Driver::scale(double x) {
mult_matrix(x,0,0,x,0,0);
}
/** see fl_translate() */
void Fl_Graphics_Driver::translate(double x,double y) {
mult_matrix(1,0,0,1,x,y);