FLTK logo

STR #3320

FLTK matrix user chat room
(using Element browser app)   FLTK gitter user chat room   GitHub FLTK Project   FLTK News RSS Feed  
  FLTK Apps      FLTK Library      Forums      Links     Login 
 Home  |  Articles & FAQs  |  Bugs & Features  |  Documentation  |  Download  |  Screenshots  ]
 

Return to Bugs & Features | SVN ⇄ GIT ]

STR #3320

Application:FLTK Library
Status:1 - Closed w/Resolution
Priority:1 - Request for Enhancement, e.g. asking for a feature
Scope:2 - Specific to an operating system
Subsystem:X11
Summary:support for high resolution displays on the X11 platform (application scaling)
Version:1.4-feature
Created By:manolo
Assigned To:manolo
Fix Version:1.4.0 (SVN: v12823)
Fix Commit:798823f7dc578c2ddef3c97b723d771381fed479
Update Notification:

Receive EMails Don't Receive EMails

Trouble Report Files:


Name/Time/Date Filename/Size  
 
#1 manolo
08:08 Jul 23, 2016
pango+scale.patch
101k
 
 
#2 manolo
04:40 Jul 26, 2016
pango+scaleV2.patch
107k
 
 
#3 manolo
00:07 Oct 16, 2016
pango+scaleV4.patch
97k
 
 
#4 manolo
09:00 Dec 21, 2016
scaling.patch
63k
 
 
#5 manolo
10:06 Dec 22, 2016
scaling2.patch
66k
 
 
#6 manolo
09:23 Jan 25, 2017
scaling3.patch
73k
 
 
#7 manolo
01:47 Jan 26, 2017
scaling4.patch
73k
 
 
#8 manolo
02:04 Feb 05, 2017
scaling5.patch
91k
 
 
#9 manolo
11:50 Feb 14, 2017
scaling6.patch
102k
 
 
#10 chris
08:23 Feb 15, 2017
test_scale_issue1.cxx
1k
 
 
#11 chris
09:50 Feb 16, 2017
test_scale_issue2.cxx
1k
 
 
#12 manolo
00:37 Feb 17, 2017
scaling7.patch
104k
 
 
#13 AlbrechtS
07:33 Feb 18, 2017
scaling7_artifacts_2.5.png
147k
 
 
#14 manolo
01:05 Feb 19, 2017
scaling8.patch
107k
 
 
#15 manolo
01:06 Feb 19, 2017
gleam240.png
0.3M
 
 
#16 AlbrechtS
02:39 Feb 19, 2017
oxy.patch
46k
 
 
#17 manolo
09:45 Feb 19, 2017
scaling9.patch
103k
 
 
#18 AlbrechtS
14:11 Feb 19, 2017
GraphicsExpose.patch
1k
 
 
#19 manolo
06:32 Feb 21, 2017
scaling10.patch
106k
 
 
#20 AlbrechtS
05:55 Feb 22, 2017
window-truncation.png
53k
 
 
#21 AlbrechtS
06:09 Feb 22, 2017
displaced_menu_Ubuntu-VM.png
108k
 
 
#22 AlbrechtS
06:10 Feb 22, 2017
displaced_menu_Cygwin_X.png
60k
 
 
#23 AlbrechtS
06:17 Feb 22, 2017
large_scaling_display.png
66k
 
 
#24 manolo
05:36 Feb 27, 2017
scaling11.patch
108k
 
 
#25 manolo
13:57 Mar 21, 2017
screenscale.patch
145k
 
 
#26 manolo
23:40 Mar 21, 2017
screenscale2.patch
145k
 
 
#27 manolo
13:40 Mar 28, 2017
screenscale3.patch
148k
 
 
#28 manolo
02:13 Mar 31, 2017
screenscale4.patch
152k
 
 
#29 manolo
10:53 Apr 09, 2017
screenscale5.patch
152k
 
 
#30 manolo
08:00 Apr 21, 2017
screenscale6.patch
152k
 
 
#31 chris
23:59 Apr 21, 2017
regression_screenscale6_help_dialog.png
28k
 
 
#32 manolo
09:59 Apr 24, 2017
screenscale7.patch
155k
 
 
#33 manolo
10:04 Apr 30, 2017
screenscale8.patch
158k
 
 
#34 manolo
09:15 May 12, 2017
screenscale+mac+win.patch
198k
 
 
#35 AlbrechtS
07:13 May 16, 2017
image_scaling_borders.png
43k
 
 
#36 AlbrechtS
08:35 May 16, 2017
editor_artifacts.png
167k
 
 
#37 AlbrechtS
16:42 May 16, 2017
offscreen_border_artifacts.png
0.7M
 
 
#38 manolo
22:40 Jun 08, 2017
scaling_rect.patch
15k
 
 
#39 manolo
23:49 Jun 09, 2017
menu_at_top.png
132k
 
 
#40 AlbrechtS
02:04 Jul 22, 2017
scaling_rect_r12346.patch
14k
 
 
#41 chris
11:55 Jul 28, 2017
read_image_downscaling_bug.cxx
1k
 
 
#42 manolo
08:45 Nov 05, 2017
scaling_rect_r12544.patch
15k
 
 
#43 AlbrechtS
12:12 Nov 05, 2017
scaling_rect_r12545.patch
14k
 
     

Trouble Report Comments:


Name/Time/Date Text  
 
#1 manolo
08:08 Jul 23, 2016
The attached pango+scale.patch gives to the fltk1.3-porting branch
support for high resolution displays for the X11 platform.
This is implemented through a new graphics driver class
Fl_Scaled_Xlib_Graphics_Driver derived from Fl_Xlib_Graphics_Driver.

An app run using the patched FLTK library will rescale all its
graphics (images included) by the ratio between the system's
dpi and 192 dpi (this ratio should equal 2 on a high resolution display).
The same app run on a "standard" display or a high resolution one
will produce graphics of the same sizes, without any source code change.

The patch also allows to use an environment variable called
FL_SCALING_FACTOR to control the scale factor for an app
before running it (for example set it to 2 and all graphics
become twice larger). This is probably a temporary feature
to allow testing without a high resolution display at hand.

The patch also incorporates support for the pango library.
 
 
#2 manolo
14:19 Jul 25, 2016
With the following improved version of function
Fl_X11_Screen_Driver::open_display() from file src/Fl_x.cxx
the support of HiDPI displays under Ubuntu should be correct:

the new code reads once at run-time the value of the
"Scale for menu and title bars" parameter of
System Settings/Displays
and use that value as scale for all FLTK drawings.

======================================

// define types needed for dynamic lib functions
typedef void GSettings, GVariant, GVariantIter;
typedef GSettings* (*g_settings_new_ftype)(const char *);
typedef GVariant* (*g_settings_get_value_ftype)(GSettings *settings, const char *key);
typedef void (*g_variant_get_ftype)(GVariant *value, const char *format_string, ...);
typedef bool (*g_variant_iter_loop_ftype)(GVariantIter *iter, const char *format_string, ...);
typedef void (*g_variant_iter_free_ftype)(GVariantIter*);
typedef void (*g_object_unref_ftype)(GSettings*);
typedef void (*g_variant_unref_ftype)(GVariant *value);

static bool ubuntu_scale_factor(float& factor) {
  // determine whether we run Ubuntu
  char line[200] = "";
  FILE *in = popen("/bin/uname -v", "r");
  fgets(line, sizeof(line), in);
  pclose(in);
  if (!strstr(line, "Ubuntu")) return false;
        // 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);
        if (!glib || !gio || !gobj) return false;
        // define pters to used functions
        g_settings_new_ftype g_settings_new_f = (g_settings_new_ftype)dlsym(gio, "g_settings_new");
        g_settings_get_value_ftype g_settings_get_value_f =
                (g_settings_get_value_ftype)dlsym(gio, "g_settings_get_value");
        g_variant_get_ftype g_variant_get_f = (g_variant_get_ftype)dlsym(glib, "g_variant_get");
        g_variant_iter_loop_ftype g_variant_iter_loop_f =
                        (g_variant_iter_loop_ftype)dlsym(glib, "g_variant_iter_loop");
        g_variant_iter_free_ftype g_variant_iter_free_f =
                        (g_variant_iter_free_ftype)dlsym(glib, "g_variant_iter_free");
        g_object_unref_ftype g_object_unref_f = (g_object_unref_ftype)dlsym(gobj, "g_object_unref");
        g_variant_unref_ftype g_variant_unref_f = (g_variant_unref_ftype)dlsym(glib, "g_variant_unref");
        // call dynamic lib functions
        GSettings *gset = g_settings_new_f("com.ubuntu.user-interface");
        GVariant *gvar = g_settings_get_value_f(gset, "scale-factor");
         GVariantIter *iter;
         char *str; int v;
         g_variant_get_f(gvar, "a{si}", &iter);
          if (g_variant_iter_loop_f(iter, "{si}", &str, &v)) {
          factor = v/8.;
 printf("name=%s value=%d factor=%g\n", str, v, factor);
        }
           g_variant_iter_free_f(iter);
        g_variant_unref_f(gvar);
        g_object_unref_f(gset);
  return true;
}


void Fl_X11_Screen_Driver::open_display() {
  if (fl_display) return;

  setlocale(LC_CTYPE, "");
  XSetLocaleModifiers("@im=");

  XSetIOErrorHandler(io_error_handler);
  XSetErrorHandler(xerror_handler);

  Display *d = XOpenDisplay(0);
  if (!d) Fl::fatal("Can't open display: %s",XDisplayName(0));

  fl_open_display(d);
  // the unique GC used by all X windows
  GC gc = XCreateGC(fl_display, RootWindow(fl_display, fl_screen), 0, 0);
  Fl_Display_Device::display_device()->driver()->gc(gc);
  
  float factor=1;
  const char *env = getenv("FL_SCALING_FACTOR");
  if (env) {
    sscanf(env, "%f", &factor);
  } else if (ubuntu_scale_factor(factor)) {
        ;
  } else {
    float hdpi, vdpi;
    Fl::screen_dpi(hdpi, vdpi);
    factor = hdpi/96;
    factor = int(10*factor + 0.5)/10.f;
  }
  if (factor != 1) {
    Fl_Scaled_Xlib_Graphics_Driver *dr = (Fl_Scaled_Xlib_Graphics_Driver*)Fl_Display_Device::display_device()->driver();
    dr->pixel_scale(factor);
  }
}

==========================================
 
 
#3 manolo
05:10 Jul 26, 2016
With attached pango+scaleV2.patch, there is, I believe, a decent
HiDPI support under Debian and Ubuntu with gnome.

The gnome scaling value is read once during fl_open_display()
and used to scale all FLTK drawing operations.
It corresponds to the value of
    gsettings get org.gnome.desktop.interface scaling-factor
on Debian, and of
    gsettings get com.ubuntu.user-interface scale-factor
divided by 8 on Ubuntu.

On other X11 systems, the dpi reported by Fl::screen_dpi()
is divided by 96 and the result is used to scale FLTK drawings.

Otherwise, env variable FL_SCALING_FACTOR can be set by the user
to a floating number to scale any FLTK apps.

The configure build accepts --enable-pango as an option.
The CMake build also can use pango as an option.

Tests on Linux + HiDPI display welcome
(has been tested here only through VirtualBox on Apple retina display).
 
 
#4 manolo
09:08 Dec 21, 2016
Attached file #4 scaling.patch has these features for HiDPI on X11:
- relative to FLTK-1.4 with (optional) pango support
- no longer uses the FL_SCALING_FACTOR environment variable
- reads the gnome scaling factor under Debian, Ubuntu, FreeBSD
and applies it to any FLTK app when it starts
- added two global shortcuts
     CTRL-'+' enlarges all drawings and windows by 25%
     CTRL-'-' shrinks all drawings and windows by 25%
(except on German keyboards, the '+' requires SHIFT)
 
 
#5 manolo
11:56 Dec 21, 2016
Attached file #4 scaling.patch should be slightly modified
to be used without pango:

in file src/drivers/Xlib/Fl_Xlib_Graphics_Driver.H,
move
  Region scale_clip(float f);
  void unscale_clip(Region r2);
outside of the #if USE_PANGO/#endif section.
 
 
#6 manolo
10:07 Dec 22, 2016
Use scaling2.patch that contains several improvements
relatively to scaling.patch.
 
 
#7 manolo
01:48 Jan 26, 2017
Use scaling4.patch that improves the window position after
ctrl-+
 
 
#8 manolo
02:08 Feb 05, 2017
Use attached scaling5.patch with new class
Fl_Scalable_Graphics_Driver. This platform-independent class
does all coordinate-scaling tasks and then calls
a platform-specific, derived class to do the drawing.

In the future, this class could be reused as is on the
WIN32 platform to better support HiDPI than what
is currently implemented.
 
 
#9 chris
02:00 Feb 13, 2017
A related observation with this (otherwise excellent patch, version 5) is, that it is seems notably slower than the unpatched FLTK-1.4 at least in extreme cases. I didn't double check though, but compiling/running a rather graphic intensive (lots of line drawing, image blitting,..) application with this patch (unscaled i.e. with scale 1.) with identic compiler flags shows a considerable slowdown. Can it be achieved somehow, that the unscaled case is unaffected in this respect?

(I have no HDPI display, and am running this patch under Ubuntu 14.04).
 
 
#10 chris
07:30 Feb 14, 2017
Ok, some figures:

I ran this drawing test program ("drawing_speed.cxx") with and w/o the patch:

#include <FL/fl_draw.H>
#include <FL/Fl_Image_Surface.H>
#include <cstdio>
#include <cassert>

int main( int argc_, char *argv_[] )
{
        fl_register_images();
        Fl_Image_Surface surf( 800, 600 );
        surf.set_current();
        Fl_Shared_Image *img = Fl_Shared_Image::get("test/pixmaps/porsche.xpm");
        assert(img);
        for ( int i = 0; i < 1000000; i++ )
        {
                fl_color( FL_RED );
                fl_line( 0, 0, 800, 600 );
                img->draw( 100, 100 );
        }
}

Without patch:

time ./drawing_speed
real 0m14.304s
user 0m1.549s
sys 0m2.188s

With patch:

time ./drawing_speed
com.ubuntu.user-interface  scale-factor name=eDP1 value=8 factor=1

(process:11672): GLib-CRITICAL **: g_variant_unref: assertion 'value != NULL' failed

real 0m36.629s
user 0m6.393s
sys 0m5.613s

So a huge difference!

The *image drawing* is the part, that looses time. One idea: Can it be, that the image does not get cached (or that it gets uncached all the time)?
 
 
#11 manolo
12:02 Feb 14, 2017
@Chris: it's good you have given a test program.
I have seen with it that all time difference results from a single
feature of the patched code:
use of Fl_Screen_Driver::offscreen_size(Fl_Offscreen, int&, int&)
to obtain the width and height of an Fl_Offscreen which
is the data cached when drawing images.
Under X11, this function makes a roundtrip between the client
and the X server. This slows down the test program at each loop
iteration.

I have modified the patch to remove this roundtrip and instead
to memorize in a new member variable of the image classes
the scaling value used when each image is cached.

In my hands (under Mac OS + XQuartz) the patched and unpatched
test programs run at the same speeds.

Could you, please, try the attached scaling6.patch on your
test program and also on your fullsize program, and report
if the speed difference has been reduced?
 
 
#12 chris
23:53 Feb 14, 2017
Yes, there is no more speed penalty with patch #6.

I am having some other issues with my application, *but only when scaling is on*. I guess it makes some assumptions that are not always valid. I'll try to pin these down to reproducable examples, but this may take some time..
 
 
#13 chris
08:22 Feb 15, 2017
Hi Manolo,
I have 2 easy to fix issues to start with. If these can be implemented I might see more clearly on other issues that are probably there:

1) I attach a small test program "test_scale_issue1.cxx". The description is included in the comments.

2) You should use rounding for the scaled coordinates/positions. This cleary improves missing dots or lines in non-integer scalings.

As a test I replaced some of the calls in Fl_Graphics_Driver.cxx with rounding versions and saw drawing errors go away in my application.

e.g.:

void Fl_Scalable_Graphics_Driver::rectf(int x, int y, int w, int h)
{
  rectf_unscaled(lround(x * scale_), lround(y * scale_), lround(w * scale_), lround(h * scale_));
}
 
 
#14 chris
09:02 Feb 15, 2017
Just noticed I posted the file "test_scale_issue1.cxx" in the "wrong" version with Fl_Double_Window commented out. Please change it to use double window.  
 
#15 manolo
14:21 Feb 15, 2017
About test_scale_issue1.cxx :
With a non-integer scaling value, say 1.5, and considering that
both FLTK and X11 use exclusively integer coordinates, there is no way
to fill the space with adjacent lines of equal width.
My conclusion is that either the application decides to use only
integral scaling values, or it paints the space with the adequate color
before painting lines.
Initializing the space with 0 would give color black. This is not a
universally valid solution. For example, white background may be
desirable in other situations.

About rounding coordinates to integer values in the patched code:
The present code is accurate for scaling values 2 and 3.
I don't know at this point if a solution is possible to obtain
pixel-accurate drawing for non-integral scaling values.
My present feeling is that rounding coordinates would not be enough.
The HighDPI displays I know use 2 as scaling value.
 
 
#16 chris
23:14 Feb 15, 2017
I am testing the patch not from the viewpoint of HDPI displays, but from its added feature of scaling applications in runtime and looking at the effect this has on *already existing* applications. Is this feature only temporary for testing HDPI code or will it remain in the final patch?  
 
#17 manolo
01:00 Feb 16, 2017
@Chris: it is extremely helpful that you test accurately
the attached patches so we can decide whether to commit this code.
Thank you very much for that.

About your question "Is this feature only
temporary for testing HDPI code or will it remain in the final patch?"
I take this feature to be: non-integer scaling factor.
I believe to be in an exploratory phase at this point
to determine whether this feature is feasible or not.
Your tests are therefore very useful.

HiDPI support achieved under the gnome desktop with
   Tweak tools ==> Windows ==> Window scaling
proposes only 1 or 2 as scaling factor values.

But, with this other route available under Ubuntu
   System Settings ==> Displays ==> Scale for menu and title bars
fractional scaling factor values are possible (e.g., 1.25).

Also, MSWindows allows fractional scaling factor values.

That is why I wanted to explore fractional scaling factor values.

At this point, I believe scaling factor values of 2 or 3 are
essentially pixel-accurate with the patch:
- line drawings reproduce with squared pixel blocks of size 2 or 3,
respectively, single-pixel states obtained at scale 1;
- fonts take advantage of the extra resolution
- shared images can do also if Fl_Shared_Image::scale() is used.
I know fractional scaling factor values create some drawing
inaccuracies. I don't know if it's possible to repair that
in general, given that both X11 and the FLTK API use only
integer coordinates. Your detailed tests and suggestions are useful.
 
 
#18 AlbrechtS
01:39 Feb 16, 2017
Manolo, thanks for doing all that, and thanks for testing @Chris.

I think that we really need non-integer scaling factors. I'm currently using 175% under Windows and in my Ubuntu VM, but I use the Virtualbox VM's scaling feature in the latter and not the scaling of the underlying Ubuntu. With my hardware resolution 3200x1800 this appears to be a good compromise between usability and scaled, effective resolution (~1828x1028).

WRT ctrl/+ and ctrl/- dynamic runtime scaling I suggest to take a look at Firefox (51.0.1) that displays its scaling factor in the address line. I see the following steps (in %): 30, 50, 67, 80, 90, 100, 110, 120, 133, 150, 170, 200, 240, 300. Chrome has: 25, 33, 50, 67, 75, 80, 90, 100, 110, 125, 150, 175, 200, 250, 300, 400, 500.

Just my 2ct. Sorry, still no time for intensive testing.
 
 
#19 chris
09:51 Feb 16, 2017
Can you have a look at test_scale_issue2.cxx?
Run the program and change the scale during it is running..
 
 
#20 manolo
00:40 Feb 17, 2017
Attached scaling7.patch should fix test_scale_issue2.cxx

It also contains an attempt to fix test_scale_issue1.cxx
and box drawing in general with fractional scaling factors.
This fix still needs testing.
 
 
#21 chris
11:38 Feb 17, 2017
I can confirm that issue2 is solved in patch #7.
Issue 1 works in 1.5 (i think it was only fixed for that scale, right?)

My application now works without flaws in all scales.

There are still issues in redrawing e.g. after moving parts of a window offscreen, best seen with all demos that use Fl_Window (not Fl_Double_Window) e.g. hello, table, subwindow,.. and after some popups or menu buttons.

mandelbrot crashes when scale is set to 0.5.
 
 
#22 manolo
00:50 Feb 18, 2017
@Chris: I am very glad to read:
    "My application now works without flaws in all scales."


I can't reproduce these issues. I use Ubuntu through VirtualBox,
are they hidden from me?
   There are still issues in redrawing e.g. after moving parts
   of a window offscreen, best seen with all demos that use
   Fl_Window (not Fl_Double_Window) e.g. hello, table,
   subwindow,.. and after some popups or menu buttons.


This will be fixed with the next uploaded patch:
    "mandelbrot crashes when scale is set to 0.5."
 
 
#23 chris
01:35 Feb 18, 2017
@Chris: I am very glad to read:
       "My application now works without flaws in all scales."

Me to. And it is really astonishing how fast this live scaling works. Nearly now impact on the performance. Great!

   I can't reproduce these issues. I use Ubuntu through VirtualBox,
   are they hidden from me?

I am on Ubuntu 14.04 with "Gnome Session Flashback" and Metacity i.e. an non-compositing WM.

And it can't be a graphics driver issue, I think, because unscaled mode is ok.

I have the same configuration in a VM too, but can't test this now. I'll do this next week if you still can't reproduce.
 
 
#24 AlbrechtS
07:33 Feb 18, 2017
Test environment: Ubuntu 16.04 in Virtualbox VM on Windows 10, using Cygwin X server on the Windows desktop. The X server runs in the native resolution (3200x1800), so this is a good test environment. The Ubuntu desktop is scaled by Virtualbox (175%), the full desktop resolution is 1824x965 (according to test/fullscreen). Gnome scaling factor is (8 and) 1.0

Test results of scaling7.patch: There are drawing artifacts with non-integral scaling factors and more. See attached file scaling7_artifacts_2.5.png with scaling factor 2.5. Details shown in the image:

(1) Line artifacts in boxes with color gradients. The shown image is with scheme 'oxy' (test) but can be seen with scheme 'gleam' as well. This was to be kinda expected when color gradients are drawn with one line per logical pixel and 1 pixel line width. How are line widths and pixel distances calculated in this case?

(2) Drawing artifacts in the clock displays. The screenshot was taken after ~40 seconds of display time.

(3) Tooltips are leaving an "empty" background when they are removed, see gray rectangle in the upper right part of the image covering partly the top row of "thin box"es. I can see this with all scaling factors (not only non-integral ones) except 1.0. This seems to depend on the WM: it is visible with the Cygwin X server, but not on the desktop (similar to Chris' observations, although I'm also using (non-compositing) WM Metacity. My guess: coordinates of expose events need to be "translated". This would also explain Chris' observation of artifacts when parts of the window are outside the screen and moved back.

Other effects (not visible in the posted image):

(4) Under Cygwin/X server on Windows desktop (not on Ubuntu desktop): when a window gets taller than the desktop height it's truncated - so far, so good. But after reducing the scaling factor the window size is scaled down proportional to the truncated size. The truncated part is lost. This happens obviously with windows that are NOT resizable, for instance test/demo.

(5) I could also see artifacts when scaling a window down after parts of it were truncated (outside the desktop). See also (3) and Chris' comments (issue 1?).

(6) After typing ctrl/+ or ctrl/- I have a tiny cursor in my Cygwin/X server environment, no matter whether I'm scaling up or down and what the scaling factor is. The size is "fixed" again whenever the cursor moves over a widget that changes the cursor (for instance any input widget). This is likely not FLTK's fault though. When the cursor is "tiny" it seems to be the default X cursor in the X server's standard size according to the native resolution. When the cursor changes back to "normal" size this appears to be the normal Windows cursor size (which is scaled by 175%).

(7) Visible in test/cursor: whenever the scaling factor is changed the cursor changes to the default cursor. Example: change cursor to FL_CURSOR_CROSS (works), type ctrl/+: cursor changes back to default. This happens in both the Ubuntu desktop and the Cygwin/X server environment.

(8) GL demo programs glpuzzle and fractals don't scale with ctrl/+ and ctrl/- (gl_overlay does).

I didn't test "everything" yet, but that should be enough for today. Sorry for the long list and many, many thanks!
 
 
#25 AlbrechtS
08:13 Feb 18, 2017
Technical notes to scaling7.patch:

(1) src/fl_boxtype.cxx: These changes should IMO not be in this patch. I understand the intention, but this would only hide symptoms (not the underlying cause). Generally we should not change any box or other high-level drawing methods (unless they are flawed anyway) because users may have similar methods in their code. If we "fix" high-level box drawing code we won't see issues users may see with their drawing functions that work(ed) w/o the scaling patch. This would imply that all changes for this feature should be in X11 specific code unless we must change some higher level driver code (classes) to support new features. And, of course, we should not try to change the gleam (and oxy) box drawing methods. They are a valuable test environment to see if pixel-exact drawing works with scaling.

(2) src/fl_draw.cxx: is this an unrelated patch that should go into branch-1.4 anyway? If yes, I suggest to commit this to svn and remove it from the patch.

(3) test/offscreen.cxx: see (2).

(4) documentation/src/osissues.dox: see (2).
 
 
#26 manolo
01:14 Feb 19, 2017
Scaling8.patch should significantly improve gradient
drawing with fractional scaling values (see gleam240.png).

There's also a new way to display scaling values.

@Albrecht:
I don't understand your test setup. Are virtualbox
and Cygwin-X both active?
How can the Oxy scheme be selected?
 
 
#27 AlbrechtS
02:39 Feb 19, 2017
Hi Manolo, thanks for the new patch. I'll try it later today (likely in the evening hours).

> Scaling8.patch should significantly improve gradient
> drawing with fractional scaling values (see gleam240.png).

Looks much better! However there are still some artifacts, but obviously you know that.

> There's also a new way to display scaling values.

How?

> I don't understand your test setup. Are virtualbox and Cygwin-X both active?

Yes, they are. Cygwin-X runs on the host (Win10) and I didn't find a way to scale it, hence it uses the native display resolution. I don't know why, but it just happens to be this way. The VM is connected by the Virtualbox network (setup: NAT) so I can start a terminal session from the Windows host to the VM that uses the Cygwin-X display. I can't go into details now (lack of time), but if you have questions I can give details.

> How can the Oxy scheme be selected?

STR #2675 has a patch, but I don't recommend using the patch directly. I have a better one in my local git repository with my new Fl_Scheme(_*) class(es), but that's still work in progress. The attached oxy.patch should apply cleanly to branch-1.4. I don't think there are significant conflicts with your patch.
 
 
#28 manolo
09:53 Feb 19, 2017
Attached scaling9.patch should fix the color gradient artefacts
with the gleam scheme, and also refrains from patching
file src/fl_boxtype.cxx.

I can't reproduce "Tooltips are leaving an "empty" background
when they are removed". I'm not in a position to fix that, then.

Cursors are drawn by X11, so the scaling factor values don't
change them.
 
 
#29 manolo
10:09 Feb 19, 2017
Could you try to do that around line 1889 of src/Fl_x.cxx
that may repair the empty-background-after-tooltip bug ?

Replace this :

  case GraphicsExpose:
    window->damage(FL_DAMAGE_EXPOSE, xevent.xexpose.x, xevent.xexpose.y,
                   xevent.xexpose.width, xevent.xexpose.height);
     return 1;


by this :

  case GraphicsExpose:
    {float s = Fl_Graphics_Driver::default_driver().scale();
    window->damage(FL_DAMAGE_EXPOSE, xevent.xexpose.x/s, xevent.xexpose.y/s,
                   xevent.xexpose.width/s, xevent.xexpose.height/s);}
    return 1;
 
 
#30 AlbrechtS
14:11 Feb 19, 2017
Attached file GraphicsExpose.patch fixes the tooltip issue and all other expose events, for instance if a part of the window was occluded by another window or dragged out of the screen and dragged back in. Please apply on top of scaling9.patch (with patch -p1), or integrate into the next version, please.

This patch is as you proposed, but adds 1 to the width and height - otherwise I could see one pixel wide lines that were left (not redrawn). That additional pixel is necessary due to rounding effects and it doesn't harm if we draw an unnecessary pixel line in case there's no rounding issue. I'm not completely sure though if rounding of the x and y coordinate (downwards) might have the effect that we need 2 (or even more?) additional pixels in the width and height values. Hard to think about that...

BTW: this patch also fixes the blank area that was left after the transitional scaling factor display window disappears if that happened to appear over the window. Yes, I found it, so my question 'How?' is answered. ;-)

That said, the other part of the patch is a great step forward. Awesome, thanks!

I can still see some strange effects, but I need more time to test and report.

Did you manage to install and use the oxy scheme patch?

PS: Just in case ... please keep these patches separate. My work on the Fl_Scheme class changes lots of code of the oxy scheme and all other schemes.

PPS: Thanks for removing and committing the unrelated patches and the changes in fl_boxtype.cxx.
 
 
#31 manolo
06:43 Feb 21, 2017
With reference to comment #24 above:

Attached scaling10.patch should fix issues 1, 2, 3, and 7

Issues 4 and 5 may also be fixed, but I can't reproduce them,
so I'm not sure.

Issue 6 may also be fixed with the fix for #7, but not sure.

Issue 8 is because glut consumes all text input, so ctrl-+ is not
seen as a shortcut by FLTK.

There are still a few drawing artefacts, but not many.

@Albrecht: it would also be interesting to test within VirtualBox
(without Cygwin-X) with the gnome desktop scaled by a factor 2.
All FLTK apps should start correctly scaled without the need to
press ctrl-+
 
 
#32 chris
07:56 Feb 21, 2017
The scale value "Scale for menu and title bars" parameter of System Settings/Displays is probably not the correct one, at least not with Gnome session flashback active. Changing it has no effect at all on the desktop, perhaps it is used only in Unity.

According to http://askubuntu.com/questions/668749/how-to-set-up-gnome-interface-for-hidpi-screen the value for Gnome is in "org.gnome.desktop.interface scaling-factor".

I tested this by adding code to the gnome_scale_factor() function in Fl_x.cxx, and it works:

  schema = "org.gnome.desktop.interface";
  if (is_schema_valid(schema, known)) {
    void *gset = g_settings_new_f(schema);
    void *gvar = g_settings_get_value_f(gset, "scaling-factor");
    void *iter;
    char str[10], *str2; int v, v2;
    g_variant_get_f(gvar, "u", &v);
    gnome_f = v;

    printf("org.gnome.desktop.interface scaling_factor name=%s value=%d factor=%g\n", str, v, gnome_f);
    g_variant_unref_f(gvar);
    g_object_unref_f(gset);
 
 
#33 manolo
13:04 Feb 21, 2017
@Chris: thanks for your input about Ubuntu + Gnome session flashback,
showing that the scaling factor should be detected differently.


Here is my current understanding:

- under Ubuntu + Gnome session flashback, the factor is changed
with gnome-tweak-tool to 1 or 2 and its value is found in
"org.gnome.desktop.interface scaling-factor"

- under Ubuntu + default desktop, the factor can be changed in two ways,
and both ways can be combined:

1) with gnome-tweak-tool to 1 or 2 and its value is found in
"org.gnome.settings-daemon.plugins.xsettings overrides"

2) with System Settings ==> Displays ==> Scale for menu and title bars
 and its value is found in
   "gsettings get com.ubuntu.user-interface scale-factor"

Thus, I changed the patch to read all 3 factor values, and to
multiply them to get the correct effect.



Why do simple when complex is so nice?
 
 
#34 AlbrechtS
05:55 Feb 22, 2017
I can confirm WRT comment #24 in scaling10.patch:

Fixed issues: 1, 2, 3, 5, 7.

Issue 4: Window truncation still happens. This is likely a WM + FLTK interaction issue. The WM seems to truncate the window but either doesn't communicate this to FLTK or FLTK doesn't recognize it. In any case, windows that are not resizable should IMO not be truncated (by the WM ?) in this way. Maybe this is a Windows "feature" since the Cygwin X server uses "Windows windows" to display the "X windows". I don't know what we can do about this.

Issue 6: There is still the tiny cursor if the cursor is not changed by FLTK to another one. Maybe we could explicitly change the cursor when a program is started or ... ?

See attached file window-truncation.png for issue #4 and #6 (the tiny cursor is visible in the middle button "Window Tests". To see the truncation effect I had to extend the scaling_values array in Fl_x.cxx:

    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, 3.75, 5.5, 6.5, 7.5, 9.75};

with values up to 9.75 just for testing. Could you please add these deliberately non-integral values in the next patch version (we can remove them before a final commit, although in my case values > 3 would really be appropriate, maybe up to 5 or 6).

The truncation effect can be seen after enlarging the window so that the physical (scaled) w and/or h are larger than the physical screen resolution. This does not happen on the Ubuntu desktop that allows a window to extend beyond physical screen sizes, and I can move the window around and see that it's intact.
 
 
#35 AlbrechtS
06:09 Feb 22, 2017
A new issue: displaced menu windows. This appears to happen when a menu window extends beyond the screen limits. I found this with test/unittest's scheme test menu (with the additional oxy scheme).

To reproduce: Use ctrl/+ to scale upwards once or more. Select 'gleam' scheme. Move the window to the top of the screen. Click on the scheme selection menu. Now the menu extends upwards beyond the window and, since the window is at the top of the screen, beyond the top screen limit. Usually this should be caught by the menu display code and corrected, but this doesn't happen (my guess: calculation doesn't take scaling into account?).

The effect on the Ubuntu desktop is benign. Once you move or drag the mouse the menu window is placed properly within screen limits, but that is still not correct.

The effect on my (Cygwin) X server on the Windows host is worse. The menu window is obviously placed at an arbitrary location by Windows. It "moves around" in the typical way like top level windows are placed on windows whenever you close and reopen the menu. I' upload two files: displaced_menu_Ubuntu-VM.png and displaced_menu_Cygwin_X.png.

I didn't test, but I assume this effect can also be seen in test/menubar.
 
 
#36 AlbrechtS
06:17 Feb 22, 2017
A minor issue: the scaling factor display may not be scaled and positioned "correctly" (for whatever that means). Attached screenshot shows shows the entire Ubuntu desktop when using the scaling factor 975%. This appears a little exaggerated.

I'd like to have the display within the window limits, maybe at the top left corner, in an adequate effective size, if this is possible.
 
 
#37 AlbrechtS
06:43 Feb 22, 2017
@Manolo, comment #31: Starting FLTK applications with different scaling factors (no matter if in Cygwin/X or Ubuntu desktop) works as expected. Unfortunately both X servers use the same setting 'VGA-1' in my case. Is this something we (you) can change? Can we add, for instance "CYGWIN-X" and use this with an arbitrary scaling factor (like 175% in my case) by using an environment variable FLTK_SCALING_MODE="CYGWIN-X" or something like that?

Original setting:

$ gsettings get com.ubuntu.user-interface scale-factor
{'VBOX0': 8, 'VGA-0': 32, 'VGA-1': 8}

Modified with:

$ gsettings set com.ubuntu.user-interface scale-factor "{'VBOX0': 8, 'VGA-0': 32, 'VGA-1': 12}"

... and the program starts with the desired scaling factor 1.5.

$ bin/examples/unittests
com.ubuntu.user-interface  scale-factor name=VGA-1 value=12 factor=1.5

(process:9817): GLib-CRITICAL **: g_variant_unref: assertion 'value != NULL' failed

PS: do you also see the "GLib-CRITICAL" assertion? There's no such message w/o the scaling patch (tested and verified).

PPS: WRT comment #33: is it really good/correct to multiply all scaling factors? Isn't it more useful to select the "right" scaling factor according to the desktop environment? Reasoning: if I need a scaling factor of 2 and switch desktops, I think that I would have to set _both_ factors (in each different desktop environment) to 2 to be effective. If you multiply them, I'd have an effective scaling factor 4 in FLTK apps, whereas the normal desktop environment(s) would have the scaling factor(s) 2. Note: that's just "thinking aloud", I have no idea how it really works. Maybe Chris can tell...
 
 
#38 chris
07:51 Feb 22, 2017
Regarding multiplication of scale factors:

I think Albrecht is right here.
I can only speak by my limited experience with only Ubuntu 14.04, but Gnome Flashback knows just "its" value and Ubuntu Unity does not use the one from Gnome Flashback (it obviously knows about it, because it resets its to 1).

So you have to choose the "right" one(s).

But how to detect which desktop type is active?

And this is only for Gnome/Unity. What about KDE and others?

My impression is, this could be much effort and will always be uncertain. I liked the initial environment variable approach. Perhaps it could be used at least as an override value for auto-detection (or unknown "systems").
 
 
#39 AlbrechtS
10:18 Feb 22, 2017
Something to think about, at least for the final solution:

If I set the Ubuntu scaling factor to 1.25 because that is my default scaling for the Ubuntu desktop, then FLTK applications start with exactly this scaling factor. That's good. Typing ctrl/+ or ctrl/- finds the nearest lower scaling factor in the list of available factors (in this case 1.20) and changes scaling to the next lower or higher factor (110% or 133%, resp.). I can never return to 1.25 again.

I suggest to change this as follows: Read the system scaling factor, whatever this is (here: 1.25) and store it somewhere. Set the internal scaling factor to 1.0, but multiply internally with the system scaling of 1.25. Now, typing ctrl/+ or ctrl/- would advance to 1.10 or 0.90, respectively, but still multiply with the system scaling (1.25) internally. The displayed scaling factor should be 100%, 90%, or 110%, resp., i.e. the "logical scaling factor" based on (multiplied with) the system scaling factor.

The end user would never see "odd" values caused by his personal desktop scaling factor. Note: this would be consistent with firefox (and chrome). The system scaling factor is never shown to the user.

This way we'd always have the initial logical scaling factor 1.0 which is effectively 1.0 * (system scaling factor). No need to search the list for an appropriate scaling factor.

Optional extension (independent of this algorithm to multiply the system scaling factor with the logical scaling factor): Add ctrl/0 key handling to reset to 100% (logical scaling factor). This would always reset to the initial scaling which would be logically 100% but physically in the described case above 125%. The display value would be 100% though.
 
 
#40 manolo
14:11 Feb 22, 2017
About these remarks in comment 37:
1) is it really good/correct to multiply all scaling factors?

2) Isn't it more useful to select the "right" scaling factor according to the desktop environment?

My current finding is that multiplying all 3 scaling factors is correct
because the two variant desktops in question seem to be aware of
each other's rescalings: change in one desktop, the change applies
to the other desktop too. So the user of two desktops won't
be tempted to rescale independently each desktop.
Also, the combined scaling value applies to all gnome apps,
so if the user would attempt to set two factors to the value 2,
he/she would immediately notice all apps (terminal for example)
get rescaled by a factor of 4.

About question #2: how can the running app detect the current desktop?
No idea.
 
 
#41 manolo
05:42 Feb 27, 2017
Attached scaling11.patch fixes several of the issues raised :
- starting with a >1 scale factor and rescaling relative to it,
- going back to the initial scale with ctrl-0,
- menu window issue,
- truncation of fixed-size windows
- FLTK_SCALING_FACTOR environmental variable used when the gnome
scale detection procedure does not work.
 
 
#42 manolo
14:03 Mar 21, 2017
Attached screenscale.patch introduces screen-specific
scaling factors. This allows to use a system with several screens
of varying DPI. Windows can be moved between screens and
adopt the screen-specific scaling.

The gnome settings determine the starting scaling,
which can be changed by ctrl-'+'/ctrl-'-'/ctrl-'0'
independently for each screen.

If no gnome setting is found, environment variable
FLTK_SCALING_FACTOR can be used to set the default
scaling value.
 
 
#43 manolo
23:50 Mar 21, 2017
Attached screenscale2.patch should fix:
- problem to build fluid with inline function

- don't multiply gnome settings values

- FLTK_SCALING_FACTOR is given precedence over gnome settings

As for a window that straddles across two displays:
Any window is drawn with the scaling factor of the screen
where most of the window's surface is located.
When the window is moved to another screen, FLTK detects
when the surface majority passes to the new screen and
schedules a redraw of the window with the new screen's scaling factor
for one second later. At that moment, the window is generally
entirely on the new window and adopts its new scale.
If it's not, it will straddle two screens but with its new scale.
 
 
#44 chris
11:31 Mar 25, 2017
Some findings:

I tested on Ubuntu 14.04 only with non integral scale factors e.g. 1.5.
and used screenscale2.patch, but my findings are not specific to that patch, they are also in previous versions:

1) There are still re-drawing artefacts with *normal* windows (not double buffered windows) as in test/hello.cxx:
   When moving the window offscreen to the left side of the screen and then back in there can be seen vertical stripes of missing pixels.

I notice that with adding 2 instead of 1 to the expose width/height in Fl_x.cxx/1717:

            window->damage(FL_DAMAGE_EXPOSE, xevent.xexpose.x/s, xevent.xexpose.y/s,
                     xevent.xexpose.width/s + 2, xevent.xexpose.height/s + 2);

these artefacts disappear.

2) test/mandelbrot.cxx has drawing artefacts with the overlay rect when selecting a zoom region.

Looking in the source it can be seen that the overlay rect is implemented by drawing 1 pixel wide images and by saving the overdrawn screen parts using fl_read_image() and restoring them before drawing the overlay rect. For some reason these two operations do not match scale-wise. Could not solve it as I could not figure out if and how fl_read_image() gets scaled, but by poking around in the code I found:

3) Using rounded values of scaled x/y/w/h can improve some things. In this case I was changing Fl_Graphics_Driver::draw_image_rescale() around line 450 in src/Fl_Graphics_Driver.cxx to use rounding:

//  Fl_RGB_Image *scaled_rgb = (Fl_RGB_Image*)rgb->copy(W * s, H * s);
  Fl_RGB_Image *scaled_rgb = (Fl_RGB_Image*)rgb->copy(lround(W * s), lround(H * s));
  delete rgb;
  if (scaled_rgb) {
    Fl_Region r2 = scale_clip(s);
//    draw_image_unscaled(scaled_rgb->array, X * s, Y * s, W * s, H * s, depth);
    draw_image_unscaled(scaled_rgb->array, lround(X * s), lround(Y * s), lround(W * s), lround(H * s), depth);


and noticed the following improvements with mandelbrot.cxx:

- no horizontal stripes (black lines) in the image
- scale factors < 1 now also show an image, previously the display was completely black.

2a) Sidenote: in fl_overlay.cxx there is a define USE_XOR that when commented in works better, but the position is not scaled with the patch.
 
 
#45 manolo
12:58 Mar 26, 2017
@Chris: thanks for your input.
I'm using Ubuntu 16.10 in VirtualBox and see
no artefact at 150% when moving around the Hello window.
I'm no sure what to do at that point.
 
 
#46 chris
22:47 Mar 26, 2017
I can reproduce it also on Ubuntu 16.04 running in VirtualBox with Metacity.

My session:

echo $DESKTOP_SESSION
gnome-flashback-metacity
 
 
#47 manolo
00:55 Mar 27, 2017
I also have here :
   echo $DESKTOP_SESSION
   gnome-flashback-metacity

A difference is I have Ubuntu 16.10

As for VirtualBox, I run 5.1.14 on Mac OS X
 
 
#48 chris
02:38 Mar 27, 2017
So maybe there were changes/fixes in Metacity after Ubuntu 16.04.
VirtualBox can be ruled out because I also get it on a real machine.
Don't have an Ubuntu 16.10 setup currently to test with.

As described, this is only on the *LEFT* screen edge.

If you can't reproduce then please ignore.
 
 
#49 chris
12:35 Mar 27, 2017
I can now reproduce also on Ubuntu 16.10, but not with the default configuration of Metacity. This is what obviously has changed from Ubuntu 16.04 to 16.10: Metacity is now configured as a "compositing  manager" by default (unlike in previous versions). So it does offscreen caching on its own and the defect is not visible.

To see it also on Ubuntu 16.10 you have to disable the "compositing-manager" flag of Metacity. This can be done with the dconf-editor (sudo apt install dconf-editor) by going to "org/gnome/metacity" and set the property "compositing-manager" to false. For some reason I get a black desktop background then, but now the drawing artefacts can be seen.

The point then is to use a non-compositing desktop manager.
 
 
#50 manolo
06:43 Mar 28, 2017
@Chris: I can now reproduce the uncomplete redraw artefact
when moving a window out and back in the left screen edge,
under Debian Linux 6.
I am still unable to exactly decode what goes wrong. I will
make this change for now
  window->damage(FL_DAMAGE_EXPOSE, xevent.xexpose.x/s,xevent.xexpose.y/s,
                 xevent.xexpose.width/s + ceil(s),
                 xevent.xexpose.height/s + ceil(s));
in the scaling patch (it also requires to include math.h).
 
 
#51 chris
10:25 Mar 28, 2017
My understanding is that it is simple the result of double rounding down of position and dimension which leads afterwards when the values are "upscaled" again in the draw routines up to 2 pixel difference.

e.g. x=100 w=100 / 1.5 => 66/66   * 1.5  ==> 99,99 i.e. an exposure region at x=99 width 99 instead position 100 width 100.

Would it not be best not to scale the X reported exposure region at all, but to pass it through to the FLTK's drawing routines "asis"?
 
 
#52 manolo
13:42 Mar 28, 2017
Attached screenscale3.patch contains the fixes suggested
at comment #44, with slight improvements.
 
 
#53 AlbrechtS
02:21 Mar 29, 2017
FYI: Regarding comment #48 and follow-up's: I can confirm the effect noticed by Chris on Ubuntu 14.04 with Metacity (non-compositing), with screenscale2.patch. This effect seems to be gone with screenscale3.patch.

However, I can still see such artifacts with scaling factors < 1.0 (for instance 0.77). These artifacts don't appear with Ubuntu 16.04 (Metacity, compositing), but that was to be expected as Chris found out.
 
 
#54 AlbrechtS
02:27 Mar 29, 2017
I found two places of suspect code in screenscale2.patch.

#1: src/Fl_Window_Driver.cxx, line #250:
 
+int Fl_Window_Driver::screen_num() {
+  if (pWindow->parent()) return pWindow->top_window()->driver()->screen_num();
+  return Fl::screen_num(x(), y(), w(), y());

----------------------------------------^^^^

should probably read:

+  return Fl::screen_num(x(), y(), w(), h());
----------------------------------------^^^^


#2: src/Fl_x.cxx:

@@ -1236,18 +1294,23 @@ int fl_handle(const XEvent& thisevent)
 
   if (fl_xim_ic && XFilterEvent((XEvent *)&xevent, 0))
       return(1);
+  Fl_X11_Screen_Driver *x11_screen_driver = (Fl_X11_Screen_Driver*)Fl::screen_driver();
   
 #if USE_XRANDR 
   if( XRRUpdateConfiguration_f && xevent.type == randrEventBase + RRScreenChangeNotify) {
     XRRUpdateConfiguration_f(&xevent);
     Fl::call_screen_init();
-    fl_init_workarea();
+#if USE_XFT
+    float factor = x11_screen_driver->default_scale_factor();
+    for (int screen = 0; screen <= Fl::screen_count(); screen++)
+      x11_screen_driver->rescale_all_windows_from_screen(screen, factor);
     Fl::handle(FL_SCREEN_CONFIGURATION_CHANGED, NULL);
+#endif // USE_XFT
   }
-#endif
+#endif // USE_XRANDR
 
   if (xevent.type == PropertyNotify && xevent.xproperty.atom == fl_NET_WORKAREA) {
-    fl_init_workarea();
+    x11_screen_driver->init_workarea();
   }
   
   switch (xevent.type) {
================================================================================


This patch appears to *remove*
  Fl::handle(FL_SCREEN_CONFIGURATION_CHANGED, NULL);
from the code path with (USE_XRANDR AND !USE_XFT).

Was this intended?
 
 
#55 manolo
07:13 Mar 29, 2017
I believe this code
int Fl_Window_Driver::screen_num() {
  if (pWindow->parent()) return
           pWindow->top_window()->driver()->screen_num();
  return Fl::screen_num(x(), y(), w(), y());
}

is correct because for a subwindow x() and y() are
the subwindow's coordinates relatively to their parent window,
whereas we need x() and y() to be a position in the screen
for Fl::screen_num(x(), y(), w(), y()) to make sense.
So, we use the top window's screen number.
 
 
#56 manolo
07:24 Mar 29, 2017
Regarding comment #53 and the fact such artifacts remain
with scaling factors < 1.0 :

I will use this new code that seems to be OK with large and small
values of the scaling factor :

      int ns = window->driver()->screen_num();
      float s = Fl::screen_driver()->scale(ns);
      int extra = ceil(s); if (extra < 2) extra = 2;
      window->damage(FL_DAMAGE_EXPOSE, xevent.xexpose.x/s,
                     xevent.xexpose.y/s,
                     xevent.xexpose.width/s + extra,
                     xevent.xexpose.height/s + extra);
 
 
#57 chris
09:21 Mar 29, 2017
@Manolo: Regarding #56, did you really find in your tests "extra" values > 2 neccessary to fix artefacts? I tested (with screenscale2.patch) many non scalar scaling factors above 2 up to 5 and never got artefacts (at least not these ones, I got others when moving below screen - but thats another story; or the rather the same in but y direction). So I still uphold my "theory" expressed in #51. And according to that adding just +2 always should suffice. Curious if that is nontheless a wrong assumption.

Regarding screenscale3.path and 2) from #44: I still get artefacts with the overlay rect, smaller ones with 1.5 but massive ones with scales < 1.
 
 
#58 manolo
09:29 Mar 29, 2017
About comment #55: please, ignore it. I had not read correctly
comment #54. The suggestion there is absolutely true.
 
 
#59 manolo
09:40 Mar 29, 2017
About part 2 of comment #54: yes, I agree the
#endif // USE_XFT
should be moved one line above.

Thanks for both suggestions.
 
 
#60 manolo
02:15 Mar 31, 2017
Attached screenscale4.patch fixes the mandelbrot test program
also for non-integer scaling factors (without changing the source
code of any test program).
 
 
#61 manolo
10:54 Apr 09, 2017
Attached screenscale5.patch also fixes the checkers test program
when moving pieces around with non-integer scaling factors.
 
 
#62 chris
23:59 Apr 21, 2017
I noted what seems to be a minor regression with clipping with screenscale6.patch, that is present even in unscaled mode. Found coincidentally when using the help_dialog test: When scrolling down to the table with images an artefact (a part of the table) appears below in the window. Attaching a screenshot.  
 
#63 manolo
10:00 Apr 24, 2017
The regression identified in comment #62 should disappear
with screenscale7.patch
 
 
#64 manolo
10:06 Apr 30, 2017
Attached screenscale8.patch supports also fractional
scaling factors for the Fl_Scroll widget by performing
full redraws.
 
 
#65 manolo
09:16 May 12, 2017
Attached screenscale+mac+win.patch adds some VERY LIMITED support of
rescaling and HiDPI support for the MSWindows and Mac OS platforms.
At this stage, it's only a proof of feasibility, that needs completion.

On the MSWindows platform:
Rescaling support is, at this stage, limited to text drawing:
only the 'hello' test program is usable (everything remains usable
without rescaling).
The patch supports GUI rescaling by ctrl/+/-/0/,
detects the current scaling factor of the OS, and
responds to changes of this value in real time.
The first feature listed above runs on all OS versions.
The other two require OS 8.1 or above.
In all cases, the text is written using the full resolution
of the display. In contrast, with the unpatched FLTK and
when the system's scaling factor is > 1, text is written
to a buffer that is then graphically expanded and copied to
the screen, producing blurred text.
The implementation is as recommended at:
https://msdn.microsoft.com/en-us/library/windows/desktop/dn469266(v=vs.85).aspx
SetProcessDpiAwareness() is called in fl_open_display() to
put the app in PROCESS_PER_MONITOR_DPI_AWARE mode.
GetDpiForMonitor() is used to compute the scaling factor value
at startup.

On the Mac OS platform:
Support for GUI rescaling by command/+/-/0/ is added.
Quite a few demo programs are partially usable (device, editor,
boxtypes, unittests, …). Since Mac OS uses a true device independent
drawing model, support for GUI rescaling is basically obtained
adding one statement in Fl_Cocoa_Window_Driver::make_current().

Part of the new code is platform-independent:
- support for rescaling by command/+/-/0/;
- the driver model gives a platform-independent interface to
the detection of the OS scaling factor and the storage of its
variable, potentially screen-dependent values;
- the Fl_Scalable_Graphics_Driver class is used twice, by the
X11 and MSWindows platforms.
 
 
#66 AlbrechtS
07:13 May 16, 2017
Testing file #33: screenscale8.patch, assuming that this would be the one to commit in branch-1.4 for now.

Observations: Image scaling and borders seem to be off by one at certain scaling factors, for instance 1.10 and 1.20. See attached file image_scaling_borders.png (supposedly file #35). This is a minor issue, but you can see a small (probably 1-pixel wide) gap between the image(s) and the border(s). Posted image is with scaling 1.10, but 1.20 is similar.
 
 
#67 AlbrechtS
07:16 May 16, 2017
Note: I used test/unittests, "drawing images".  
 
#68 AlbrechtS
07:44 May 16, 2017
Unexpected behavior of test/blocks: this demo program obviously uses the '+' key to switch to the next level (I didn't know that, and I didn't check the code). The unexpected behavior is that the program also gets the ctrl/+ key press that adjusts the scaling factor and then also switches to the next level. This can only be observed after the game has been started with the start button.

The question/issue: shouldn't the ctrl/+/-/0 key press be consumed by the scaling feature? In this case (blocks) it would certainly be good not to deliver the ctrl/+ event to the application, but in other cases I don't know what to suggest. It might be useful to use _and_ deliver it anyway to not hide it from the application's key events.

Blocks could be changed to ignore ctrl/+ (i.e. use the '+' key only w/o ctrl being pressed), but in case of other applications this might not be feasible.

Opinions?
 
 
#69 AlbrechtS
08:07 May 16, 2017
Unexpected behavior of test/offscreen: when changing the scaling factor with ctrl/+/-/0 the offscreen drawing is reset and restarted. This seems to be due to an FL_HIDE event that is seen by the application (tested and verified).

I believe this is necessary to change the scaling factor (is it?), but it may have side effects user applications.

Another side effect is that dialog windows appear to be closed and this may affect applications. Example: run test/ask, wait a few seconds until a popup appears. Recognize the color of the dialog icon with '?'. Then press ctrl/+ to change the scaling. The icon color changes (not always, but at least sometimes [1]), as if the dialog had been answered with the <esc> key. This is a behavior change that can affect applications.

[1] the color change appears if another timeout has been queued in the background which happens every 5 seconds.

Conclusion: There are behavior changes of programs that observe FL_HIDE and FL_SHOW events if the user changes the scaling factor. Should we accept these potential changes and document them? We could document the restriction and recommend not to change the scaling factor too frequently, i.e. only after program start or when really required?
 
 
#70 AlbrechtS
08:35 May 16, 2017
I can see artifacts on the window border (!) of test/editor when using a scaling factor > 1.0 and resizing the window. You can see these artifacts in the attached image editor_artifacts.png (file #36). Some of the pixels on the right and bottom border seem to be green (from comments), others are black. It looks as if the text rendering can somehow exceed the client area and draw over the window borders. Very strange...

Another observation in the same image is that the beginning '//' on otherwise "empty" lines are truncated on the upper right side. ISTR that this was already reported (maybe by Chris?), but I couldn't find it right now.

Both observations may be related (text measurement). IIRC someone (Chris?) reported that replacing fl_measure() with fl_text_extents() helped to fix at least the 2nd (i.e. '//') issue. But I wonder if calling fl_text_extents() in Fl_Text_Display/Editor might be too expensive and slow text rendering down.
 
 
#71 chris
09:15 May 16, 2017
Regarding #70 - cut off // in text display: My report is in http://www.fltk.org/str.php?L3364

This is nothing new, has been so "forever".
 
 
#72 ianmacarthur
09:33 May 16, 2017
Regarding #69: I think we need to document that there may be an issue with FL_SHOW/FL_HIDE events during a "zoom change", but I'm not sure three's much we could do to "fix" it.

For example, if we need to destroy and recreate the context (as I assume happens in the offscreen demo, for example) then I can't really see how we would "preserve" the prior image but somehow resize it to suit the new context.
In that case, would we try to rescale the content of the existing offscreen buffer and use that to fill the new buffer initially?
That doesn't sound easy.

Similarly with dialog boxes and similar; I guess our best bet might be just to persuade users *not* change zoom factor with the dialogs displayed!  :-)
 
 
#73 AlbrechtS
14:48 May 16, 2017
Regarding #72: Ian, there are two different points we need to check/discuss:

#1: Do we really need to hide and show the window(s) in the first place? Would just resizing the window not be sufficient? I have to admit that I don't know what's going on under the hood (need to check the sources), so this is basically a question to Manolo.

#2: The offline demo was mentioned by me as an example *user* program that changes its behavior when the user types ctrl/+/-/0. So the question is not how we can fix the offline demo program (or the blocks demo, or other programs with open dialogs), rather than how to fix the FLTK core so that user programs are not affected by the changes - if at all possible.

So if we can't avoid hide() and show() then we have to live with the consequences. As you wrote, if we can't change it, we can only document it and ask users to take care when changing the scaling. The new zoom feature is IMO worth much more than we lose because of these small side effects.
 
 
#74 ianmacarthur
15:21 May 16, 2017
Re: #73 (2) - I imagine (without investigating...) that what happens is something like this.

The offscreen surface is essentially a surface at the native resolution of the display, and what is drawn into that surface persists across updates.
Drawing into that surface happens at whatever scale factor is currently set. So if the offscreen is nominally 512x512, and the scale is 2, we actually draw a 1024x1024 surface.

When the scale factor is changed, a new offscreen is created sized to suit at the new scale. But everything that is "stored" in the "old" offscreen is now the "wrong" size, so can not be just copied over.

We can discard it (which seems to be what happens now) or perhaps we could try to resample it to the new size, albeit with some loss of fidelity in the process, potentially?

I'm not keen on trying to resample, though perhaps the user could do that if they needed to? Do not know.

And I may be totally wrong about what is happening here anyway!
 
 
#75 AlbrechtS
16:35 May 16, 2017
Re: #74: Your description seems to be correct, but it's maybe much simpler. The offscreen demo reacts on FL_HIDE events and destroys the offscreen when it receives an FL_HIDE event. It creates another empty offscreen when needed (i.e. after FL_SHOW). You can see the same effect if you hide and show the window with the WM buttons. So far this behavior is intended. The code is in lines 116-120 of test/offscreen.cxx:

 116    if (ev == FL_HIDE && oscr) {
 117        fl_delete_offscreen(oscr);
 118        oscr = 0;
 119        iters = num_iterations + 1;
 120    }

However (I apologize if that was clear) this was *not* my point. Maybe my explanation was not clear enough. I'm not interested in how we can fix end user programs because we can't do that. So the question what exactly happens inside test/offscreen is moot.

My point is that the offscreen demo is only one random example of an *end user* program. IMO our new features should not affect end user programs in a way that their behavior is changed, which obviously is the case in this demo (user) program. The existence of FL_HIDE and FL_SHOW events when the user types ctrl/+ is an unexpected behavior (side effect) of the new feature which should be avoided if possible. Other end user programs may suffer from these additional events as well.

Hence we are back to the relevant question: whether we can avoid the FL_HIDE and FL_SHOW events for backwards compatibility without unexpected side effects.
 
 
#76 AlbrechtS
16:42 May 16, 2017
BTW: while I was testing I found that the offscreen demo also shows artifacts drawn over the window borders (or what appears to be the window borders).

Test scenario: run test/offscreen, scale down to 50% with ctrl/-, then resize the window by dragging the bottom right corner. While dragging, watch the border (or release the mouse to see what happens). Depending on the current size, there is a part of the border that seems to contain offscreen drawing info.

See attached file (#36):
http://www.fltk.org/strfiles/3320/offscreen_border_artifacts.png
 
 
#77 manolo
09:06 May 17, 2017
About comments 73 & 74: what Ian writes is entirely accurate:
the pixel size of the offscreen buffer depends on the scaling
factor value, so the offscreen buffer needs be changed each time the
application window is rescaled.
When the app is rescaled, the widths of the lines drawn also vary
according to the new scaling factor.

Doing otherwise would require to rescale the offscreen to another
width and height. That is possible in itself, but requires that
FLTK has a handle to this offscreen, which is not the case.
Only the app knows it's working with an offscreen buffer.
 
 
#78 manolo
09:18 May 17, 2017
About comment #73:

The present code does
  Fl::screen_driver()->scale(screen, f);
  window->hide();
  window->show();
where f is the new scaling factor and screen is the number of the
window-containing screen, to trigger the rescaling of an FLTK window.

This source code is platform-independent and works well
on all 3 platforms.

I have tried other ways, but they fail for subwindows. The difficulty
is that rescaling is a window resize in drawing units, but changes no
value in FLTK units, the only unit that FLTK considers in its resizing
algorithm.

If a developer finds another way, that would be excellent.
The code part to consider is function
   Fl_Screen_Driver::rescale_all_windows_from_screen()
in file src/Fl_Screen_Driver.cxx
 
 
#79 manolo
09:46 May 17, 2017
About unwanted side effects of hide()/show() when rescaling windows:

The offscreen program reveals one issue with offscreen buffers.
Not all offscreen buffers create problems though. Those
associated to images are handled internally by FLTK which recomputes
them if needed after a rescale.

We could add an
   Fl_Offscreen fl_offscreen_rescale(Fl_Offscreen off, float s)
convenience function to help users rescale their offscreen buffers?

Another issue: the fl_width() of a character of a fixed-width font
is not strictly proportional to the scaling factor, because scaling
factors can be non integer whereas FLTK font sizes are always integer.
Consequently, an app that multiplies this width by a somewhat large
number to compute horizontal offsets will need to recompute it after
each window rescale.
 
 
#80 manolo
10:32 May 18, 2017
I have committed (r.12240) a new function
   void fl_scale_offscreen(Fl_Offscreen &)
that scales an offscreen buffer after the scaling factor
value was changed.
The offscreen test program calls it, and is able to keep
the content of its offscreen drawing across rescale operations.

We could document the usage of this function when dealing
with HiDPI and scaling support.
 
 
#81 manolo
23:00 Jun 08, 2017
Attached file #38 (scaling_rect.patch) is a proposal
to fix the issue described here at #66.
The point is more generally that there should be no
undrawn pixels between fl_rect(x,y,w,h) and
fl_rectf(x+1, y+1, w-2, h-2).

The patch does that for all scaling values, and also if
fl_loop() is used instead of fl_rect().

Consequently, there are no more undrawn pixels inside rectangles
of the "rectangles" and "drawing images" modes of the unittests
program, at all scales.

Consequently, rectangles are drawn with sides that can
have different widths, to compensate for non-integer
coordinates.

@Albrecht: what is the preferable graphical effect:
- rectangles with equally wide sides, but undrawn pixels inside
- no undrawn pixels, but rectangle sides have variable widths
?
 
 
#82 manolo
08:39 Jun 09, 2017
About comment #68 and test/blocks:

I believe the problem is in the source code of the test/blocks program.
It detects the '+' key only by testing
    strcmp(Fl::event_text(), "+") == 0
This test is also positive with ctrl-'+'. The test should thus
make sure that Fl::event_command()is false.
Moreover, when the '+' key is processed, the handle() function
returns 0, indicating the key event has not been recognized.
Consequently, the key event becomes processed by the event handler
in charge of the detection of enlarge/shrink commands.

Overall, I believe this modified form of the source code is necessary:
    case FL_KEYBOARD:
      if (!Fl::event_command() && Fl::event_text()) {
          if (strcmp(Fl::event_text(), "+") == 0)
            up_level();
            return 1;
        }
        break;

@Albrecht: what do you think? You wrote
   "The question/issue: shouldn't the ctrl/+/-/0 key press
    be consumed by the scaling feature?"
I believe the blocks program should consume
the '+' key event when it detects it, that is, have the
handle() return non-zero, so it does not get sent after
to the scaling feature. If the absence of the ctrl modifier
is also tested by the blocks program, all things run well
because the scaling feature requires this modifier.
 
 
#83 manolo
23:14 Jun 09, 2017
With r.12255, the window border artefact described at
comment #70 should disappear.
 
 
#84 manolo
23:57 Jun 09, 2017
About comment #35: displaced menu windows.
With the present code, I see no effect of scaling,
because the menu window behaves equally for scaling
factors =1 and >1.

I added a few dummy elements to the schemes menu
of test/unittests so it goes above the window top
end when the last menu item is selected.
With and without rescaling, the menu is positionned
equally, as if the window would be taller (see
attached #39 menu_at_top.png). This is with Debian.
 
 
#85 AlbrechtS
02:04 Jul 22, 2017
Uploading new version (#40) of file #38 (scaling_rect.patch) for current svn (r12346).
http://www.fltk.org/strfiles/3320/scaling_rect_r12346.patch
 
 
#86 chris
03:06 Jul 22, 2017
I found there is a minor behaviour regression (compared to FLTK 1.3) caused by manual zooming with Ctrl+ and Ctrl-.

Consider this program:

----------------
#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>

class MainWin : public Fl_Double_Window
{
public:
   MainWin( int W_, int H_, const char *l_ = 0 ) : Fl_Double_Window( W_, H_, l_ ),
      _toolBox( 0 )
   {
      end();
      _toolBox = new Fl_Double_Window( 200, 200, "toolbox" );
      _toolBox->end();
      _toolBox->show();
      show();
   }
   virtual void hide()
   {
      Fl_Double_Window::hide();
      if ( _toolBox )
         _toolBox->hide();
   }
private:
   Fl_Double_Window *_toolBox;
};

int main()
{
   MainWin win( 800, 600, "main" );
   return Fl::run();
}
----------------

It tries to hide all windows ('toolBox' here), when the user clicks on the close button of the main window in order to cause an exit. It does so by overriding the hide() method of the main window, in the believe, that only the close button of the main window will trigger this method. I think this is a valid assumption for FLTK 1.3.

Now with FLTK-1.4 the manual zoom currently calls the virtual hide()/show() methods too. The effect on this program is, that the 'toolBox' window gets hidden and won't reappear after the scaling.


I suggest the following patch, that calls only the base class hide()/show() methods:

Index: src/Fl_Window_Driver.cxx
===================================================================
--- src/Fl_Window_Driver.cxx (Revision 12346)
+++ src/Fl_Window_Driver.cxx (Arbeitskopie)
@@ -263,7 +263,7 @@
 void Fl_Window_Driver::resize_after_scale_change(int ns, float old_f, float new_f) {
   int oldx = pWindow->x(), oldy = pWindow->y();
   fl_uintptr_t current = current_cursor();
-  pWindow->hide();
+  pWindow->Fl_Window::hide();
   screen_num(ns);
   pWindow->position(oldx*old_f/new_f, oldy*old_f/new_f);
   force_position(1);
@@ -271,7 +271,7 @@
     pWindow->size(pWindow->w() * old_f/new_f, pWindow->h() * old_f/new_f);
   }
   Fl_Graphics_Driver::default_driver().scale(new_f);
-  pWindow->show();
+  pWindow->Fl_Window::show();
   reuse_cursor(current);
   reuse_icons();
 //extern FILE*LOG;fprintf(LOG,"ns=%d old_f%.2f new_f=%.2f\n",ns,old_f,new_f);fflush(LOG);
 
 
#87 manolo
03:30 Jul 23, 2017
@chris:

The solution you propose is not possible because Fl_Widget::hide()
is a virtual member function with several implementations,
in particular, distinct implementations for the Fl_Window
and Fl_Double_Window classes. Thus, calling Fl_Window::hide()
would be incorrect for an Fl_Double_Window object.

What you should do is provide your main window with a callback function,
because the window's callback is what is triggered when the
window's close button is clicked, as explained there:
    http://www.fltk.org/doc-1.3/classFl__Window.html#details

The default window callback calls hide() (as a virtual member
function) for the window. Since you want more than that, you
just have to implement what you want in a callback function and
assign it to your main window. This is a working implementation:

#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>


void mainwin_cb(Fl_Widget *wid, void *data) {
  bool found;
  do  {
    found = false;
    Fl_Window *win = Fl::first_window();
    while (win) {
      Fl::delete_widget(win);
      found = true;
      break;
      win = Fl::next_window(win);
    }
  } while(found);
}


class MainWin : public Fl_Double_Window
{
public:
  MainWin( int W_, int H_, const char *l_ = 0 ) : Fl_Double_Window( W_, H_, l_ )
  {
    end();
    _toolBox = new Fl_Double_Window( 200, 200, "toolbox" );
    _toolBox->end();
    _toolBox->color(FL_BLUE);
    show();
    _toolBox->show();
    callback(mainwin_cb);
  }
private:
  Fl_Double_Window *_toolBox;
};


int main()
{
  MainWin win( 600, 400, "main" );
  return Fl::run();
}
 
 
#88 manolo
03:40 Jul 23, 2017
OK, a quite simpler implementation of mainwin_cb is enough:

void mainwin_cb(Fl_Widget *wid, void *data) {
  Fl_Window *win;
  while ((win = Fl::first_window()) != NULL) Fl::delete_widget(win);
}
 
 
#89 chris
09:58 Jul 23, 2017
#87: Mainly I wanted to point out, that code working with FLTK 1.3, could get a problem when compiled with FLTK 1.4 and manual zooming is done (as was the case with my code).

You are right, that my proposed solution (though it seemingly works with all test programs), may have problems (what I can see: the deletion of the offscreen is not done with double windows), but those might be solvable by moving more code to the driver class. But I also noticed, there are more such hide()/show() metaphers in the code e.g. Fl_Window_Driver::use_border(), so unless all of these get changed, there were not advantage changing this one.

But on the other side, it is arguable, if overloading hide() with the purpose I used it for, is good practice. Probably not. So looks, as if I got to change my program, the way you outlined it. Thanks.
 
 
#90 chris
10:00 Jul 23, 2017
By the way: Skimming through source I noticed Fl_Overlay_Window.cxx, line 30 may have the same issue that was fixed in r12339.  
 
#91 AlbrechtS
10:38 Jul 23, 2017
Re #86: this is not a trivial issue, and I have several, potentially contradicting "opinions":

(1) I agree that this is a behaviour change (maybe we can call it a regression) WRT FLTK 1.3.4. I would really, really prefer a solution that does not call hide() and show() on all windows, but as long as we don't have such a solution (that also works cross-platform) this may be something we have to live with in FLTK 1.4 and later. We discussed already that we need to document it thoroughly, but we know that there may be impacts on user code.

(2) I agree with Manolo that not calling the virtual method(s) hide() and show() would be wrong, with potentially more, yet unknown, consequences. I remember that we made show() and hide() virtual at some time for a good reason, probably in the development of FLTK 1.3.0 (sorry, too lazy to check now).

(3) I disagree with the assumption that "only the close button of the main window will trigger this method" (hide()). Although it may be valid for your program in this case, the WM may also hide() and show() windows, for instance if you switch desktops or do some other things - although I'm not aware of such a WM, I'm only imagining that this _might_ be possible. Manolo showed the recommended FLTK way to deal with the close button by defining a window callback. This is well documented and should always be followed.

(4) Another way to handle the issue is to also provide a virtual show() method for your example program, like this:

   virtual void show()
   {
      Fl_Double_Window::show();
      if ( _toolBox )
         _toolBox->show();
   }

A small side effect of this is that the window that gets the focus after ctrl +/- may change, so I can't really recommend this.

Conclusion: I know this is a code change that becomes necessary with the transition from FLTK 1.3 to 1.4 (be the program "correct" or not), and I'd really like to avoid this, but ... go back to (1) ;-)
 
 
#92 manolo
23:38 Jul 23, 2017
@Chris Re #90: Good catch! It's now fixed in the svn repository (r.12347)  
 
#93 manolo
04:04 Jul 25, 2017
Albrecht special: with r12349, branch 1.4 no longer calls
Fl_Window::hide() and show() to rescale windows in response
to ctrl-+/-/0/
This is now done by a call to Fl_Window::resize(), but
requires some tweaking of this function.
A new boolean flag has been created, static member variable
bool Fl_Window_Driver::in_resize_after_scale_change,
that is true if and only if Fl_Window::resize() has been
called by Fl_Window_Driver::resize_after_scale_change().
This flag makes Fl_Window::resize() correctly rescale
any window.
 
 
#94 AlbrechtS
05:06 Jul 25, 2017
Re #93: That's great news. Awesome, thank you very much! I'll test ASAP.  
 
#95 chris
11:57 Jul 28, 2017
Is there something awry with fl_read_image()?
I have posted a program at #41 that shows garbage when scaling down and ultimately crashes when 50% is reached.

(Ubuntu 14.04)
 
 
#96 manolo
00:42 Jul 29, 2017
Yes indeed.
This should be repaired now in the svn repository (r.12365).
 
 
#97 chris
12:43 Jul 29, 2017
Yes, this works now.

It looks as if src/Fl_Widget_Surface.cxx has the same source pattern at line 162, would it also need a change?
 
 
#98 manolo
08:22 Jul 30, 2017
Re #97: correct. This is now fixed in the svn repository (r.12366)  
 
#99 greg.ercolano
01:27 Nov 04, 2017
Wow, this is amazing!!

I'll be recompiling my apps with 1.4.x this weekend to test.

So far so good.. the only thing I've noticed so far is how
tabs vs. spaces indented code appears in Fl_Text_Display/Editor;
at the fractional scales between 1 and 2, the columns go out of
alignment a bit. And selecting over the text causes the text to wobble.

Looks fine in Fl_Multiline_Input.

So it's probably something /just/ in the Fl_Text_Display code's
tabstop calculations.
 
 
#100 greg.ercolano
14:47 Nov 04, 2017
Augmenting the title of the STR to include the word 'scaling'..  
 
#101 manolo
07:48 Nov 05, 2017
RE: comment #99
This should now be fixed with r.12544.
 
 
#102 manolo
09:33 Nov 05, 2017
Progress report about STR#3320:
  Support for high resolution displays on the X11 platform
5 november 2017

The X11 and WIN32 platforms support runtime rescaling of all
FLTK-created windows by ctrl-+/-/0 keys.

Nothing new about rescaling for the MacOS platform (but 'retina'
displays are fully supported since 1.3.4).

The X11 and WIN32 platforms support screen-specific scaling factors.
Consequently, desktops mixing displays of distinct resolutions are well
supported. When an FLTK window is moved between screens with different
resolution, it gets automatically rescaled (actually, this is done using
a 1-second timeout).

Under MSWindows, Debian, Ubuntu, FreeBSD, FLTK attempts to discover
the desktop scaling factor at work at application start, and
applies this factor. Consequently, FLTK apps run well on HiDPI displays.

If this mechanism fails, the environment variable FLTK_SCALING_FACTOR
can be set to indicate the desired scaling factor (example: 1.75).

The all new Ubuntu 17.10 has changed its way of storing the desktop
scaling factor, so that the environment variable is needed there.
[Wanted: where does Ubuntu 17.10 store this scaling factor value?]

Adjacent horizontal and vertical lines and adjacent rectangles (in
FLTK units) are drawn so that there is no undrawn space between them
(in graphical units). Consequently, gradients used in FLTK schemes and tiled images work correctly when the scaling factor has a non-integral value.

FLTK apps should generally acquire correct rescalability without source
code change with FLTK 1.4. One type of operation does not rescale
correctly, though, with non-integral scaling factor values: operations
that assume fixed-width characters to have integral widths. Decimal-
valued factors create decimal-valued character width (in FLTK units).
If this value is truncated to int and multiplied, the resulting value
can be far from correct. I have seen this effect in one full-size
app. The app was fixed by recomputing the fixed character-width after
each scaling operation. This effect is also the ultimate cause of
the problem reported at comment #99 (now corrected in svn).

A choice remains to be done between two approaches:
    1) use the code of the svn repository
    2) apply scaling_rect_r12544.patch (attached file #42)

They differ in how empty rectangles and successive horizontal and
vertical lines - with, e.g., fl_xyline (int x, int y, int x1, int y2) -
are drawn. In case 2), FLTK makes sure there is no undrawn space
between fl_rect(x, y, w, h) and fl_rectf(x+1, y+1, w-2, h-2),
or between fl_rect(x, y, w, h) and fl_rect(x-1, y-1, w+2, h+2).

Program test/unittests allows to compare the outcomes of the two approaches:

With 2) no red is visible in the "rectangles" test even with
non-integral scaling factor values, and there's no undrawn space
between image and box in "drawing images". But "drawing lines" shows
that line width depends on line position (resize the window to modify
line positions and see varying line widths).

With 1), the segments of broken lines and of empty rectangles have all
the same width. But, there's undrawn space when an empty rectangle is
nested within a one unit-larger empty rectangle, or filled by a one
unit-smaller filled rectangle.

1) and 2) don't differ (and don't matter) when the scaling factor has
an integral value (1, 2 or 3). The issue results from the conflict
between a graphical system with all-integral values (X11 or WIN32-GDI)
and non-integral scaling factor values that ask for drawing at
fractional coordinates.
 
 
#103 AlbrechtS
12:12 Nov 05, 2017
Uploaded file scaling_rect_r12545.patch adjusted to current svn (r12545).

@Manolo: The only difference to scaling_rect_r12544.patch is the omission of the hunk related to documentation/Doxyfile.in that has been updated by me to fix a documentation build warning in out-of-source CMake builds. I also added the two missing excluded files that were added by your r12544 patch, and, btw. sorted the list alphabetically. Please update your working copy before you try to commit...

Thanks for the summary of changes.

I'm pretty sure the mentioned patch is worth being committed. The code is much cleaner and I believe it does what it should do by drawing lines and rectangles "better" for non-integral scaling factors.

+1 for scaling_rect_r12545.patch
 
 
#104 greg.ercolano
12:37 Nov 05, 2017
Are there user documents the applications can point users to
for how to control scaling FLTK apps in e.g. KDE and MS Windows?

I'm kinda new to all this; I take it there's perhaps the scaling value
is something the user sets as a window manager option, and that can be
polled from the app as a window manager "hint" maybe?

And this "hint" is a single floating point value passed to the app
that this STR gets from the window manager, so that when the user
sets the scaling value to, say, 150%, the apps always open with that
scaling?

I was thinking I should adjust my app's user preferences, which keeps
track of things like the user's last resize and position for the window,
font/scheme/color preferences, and include this new scaling value, so
that if the user uses Ctrl+/Ctrl- to change the size, I can save this
value whenever it changes in the app's preferences.

But maybe I shouldn't do that if the window manager keeps track of this?
Or does the window manager just recommend a starting value (say 150%),
and the user's Ctrl+/Ctrl- actions adjust that value up/down? If so,
does the window manager keep track of it for the app, or should our
apps keep track of this?
 
 
#105 AlbrechtS
13:10 Nov 05, 2017
FLTK's internal scaling factor is initialized with the system's (i.e. MS Windows' or under Linux with the desktop environment's) scaling factor. AFAICT there is no user documentation in FLTK that describes how to change the system's scaling factor and there are very different ways to do this. Under MS Windows there's a scaling option somewhere in the display settings (I'm using 175%, for instance), but the different desktops under Linux vary. In my personal Linux VM I don't use the Linux scaling options: the scaling is done by VirtualBox settings. YMMV.

This initial (system) scaling factor can be overriden by the environment variable FLTK_SCALING_FACTOR as Manolo described. This always takes precedence if defined.

The user's changes to the scaling by ctrl/+/-/0 is additional to the initial scaling factor, technically correct it is multiplied with the initial scaling factor to the user gets the impression that the system scaling factor is the default scaling and they can return to the system scaling with ctrl/0.

I wouldn't recommend to save this additional user scaling in a preference w/o asking the user to do so because one may use it only temporary in a specific situation. It can also be wrong to save the user value if the user later changes the system setting because the user setting will be multiplied on top of the changed system scaling value.

That said, I don't think that the application can currently access FLTK's internal/calculated scaling factor. Manolo may know that better (or add an accessor method ?).

To your last question: the WM doesn't know of FLTK's internal scaling. There is only the desktop scaling value that the WM or desktop environment keeps track of.
 
 
#106 manolo
23:48 Nov 05, 2017
The current scaling factor value is given, in a
platform-independent way, by:
   float  Fl_Graphics_Driver::default_driver().scale()

MSWindows sets a default scaling value for each screen of the
desktop that depends on the screen size (or size and resolution?).
Then, the user can tweak this value using system preferences.
Each FLTK app reads these values for each screen at startup
and uses them. The app user can further increase/decrease them
by ctrl/+/-/, and reset them by ctrl-0.

KDE has a desktop scaling value set using the system preferences
mechanism. Unfortunately, I did not find how to get this value
from an app. The FLTK_SCALING_FACTOR environment variable gives
a workaround.

Gnome also sets a desktop scaling value through system preferences.
Until Ubuntu 17.10, it was possible to recover this value through
the "gsettings" command (and a corresponding C API).
Ubuntu 17.10 changed that. No idea where the value is hidden now.
Help wanted for Ubuntu 17.10 and KDE.

It will be useful to write about that in the FLTK doc.
 
 
#107 manolo
01:37 Nov 06, 2017
Complement to comment #102: Progress report

The current implementation requires to set the preprocessor
variable FLTK_HIDPI_SUPPORT to 1 for the new code to be
active under the WIN32 platform.

Without that, FLTK apps are so-called DPI-unaware: they
run on HiDPI displays because the system expands all their
graphical output before putting it on screen. This is the
situation as of FLTK 1.3.
 
 
#108 manolo
07:17 Dec 18, 2017
As of r.12595 (18 dec 2017), the new feature is mostly completely
implemented in FLTK 1.4.
 
 
#109 chris
01:35 Apr 01, 2018
Found by incidence, that there is a drawing artefact with Sliders at scale 200% with scheme gtk+.
As this is an integral factor, I wonder how this can happen.

System: Ubuntu 14.04

To reproduce:

test/valuators -s gtk+
Set 200%
Move the (red) slider knobs.

They are leaving 1px horizontal and vertical red line artefacts.
 
 
#110 ianmacarthur
13:51 Apr 01, 2018
Hmm, I'm not seeing that - but I do see errors.

I don't see the red lines Chris describes, but I am seeing artifacts left on the red sliders in the valuators test, in gtk++ mode, at *all* zoom factors, not just 200%.

I do not recall seeing this before - but that probably only means I didn't look properly...
 
 
#111 AlbrechtS
09:39 Apr 02, 2018
Ian, did you test on Windows? I can confirm artifacts on Windows with all scaling factors greater than 1 (that I tested).

I can also see artifacts on Linux (as Chris reported) with scaling factors > 1.75. These artifacts seem to disappear if I set line_delta_ = 0 for all scaling factors:

--- a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.cxx
+++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.cxx
@@ -93,6 +93,6 @@ void Fl_Xlib_Graphics_Driver::scale(float f) {
      coordinates by line_delta_ achieves what is wanted until scale_ <= 3.5.
      */
-    line_delta_ =  (scale_ > 1.75 ? 1 : 0);
+    line_delta_ = 0;
   }
 #endif
 }
 
 
#112 chris
10:07 Apr 02, 2018
> These artifacts seem to disappear if I set line_delta_ = 0 for all
> scaling factors:

But this seems not to be the cure, it results in symptom shift only.

e.g.:

- all windows have artefacts at right and bottom edge at 200%
- test/tiled_image moved around screen edges gets horizontal stripes at 200%
 
 
#113 AlbrechtS
10:19 Apr 02, 2018
chris wrote in comment #112:
>> These artifacts seem to disappear if I set line_delta_ = 0 for all
>> scaling factors:
>
> But this seems not to be the cure, it results in symptom shift only.

Sure, I was aware of this. I only wanted to mention it to point out that the issue may have something to do with the way line_delta_ is applied to graphics functions. Sorry for the confusion.
 
 
#114 manolo
05:25 Apr 05, 2018
The drawing artefact with Sliders at scale 200% and with scheme gtk+
should be fixed with r.12821.
 
 
#115 AlbrechtS
07:46 Feb 08, 2019
Fixed in Git repository.

There has been another update in svn r12823, Git commit 798823f7dc...
I updated the revisions accordingly.

I believe it's all done on all platforms and in case someone finds any glitches they can open a new and more specific STR.

Manolo, can we close this STR?
 
 
#116 manolo
08:25 Feb 08, 2019
Fixed in Git repository.

Support for high resolution is present in FLTK 1.4 for
all 3 platforms, really: X11, Windows, macOS.
 
 
#117 AlbrechtS
05:56 Feb 17, 2019
Test, please ignore. Sorry for the noise.  
     

Return to Bugs & Features ]

 
 

Comments are owned by the poster. All other content is copyright 1998-2024 by Bill Spitzak and others. This project is hosted by The FLTK Team. Please report site problems to 'erco@seriss.com'.