# HG changeset patch
# User Pantxo Diribarne <pantxo.diribarne@gmail.com>
# Date 1523525900 -7200
#      Thu Apr 12 11:38:20 2018 +0200
# Branch stable
# Node ID f51c8af17df7fcde14c091445828221836637025
# Parent  1b1b29705d532372e7b7cd17d9fc179ce1b9720f
[mq]: per_figure_displaypixelratio_2018Apr05.diff

diff -r 1b1b29705d53 -r f51c8af17df7 libgui/graphics/Figure.cc
--- a/libgui/graphics/Figure.cc	Mon Apr 09 11:33:21 2018 -0700
+++ b/libgui/graphics/Figure.cc	Thu Apr 12 11:38:20 2018 +0200
@@ -41,6 +41,8 @@
 #include <QtDebug>
 #include <QTimer>
 #include <QToolBar>
+#include <QWindow>
+#include <QScreen>
 
 #include "Canvas.h"
 #include "Container.h"
@@ -133,6 +135,11 @@
 
     figure::properties& fp = properties<figure> ();
 
+    // Register for the signal that indicates when a window has moved
+    // to a different screen
+    connect (win, SIGNAL (figureWindowShown ()),
+             this, SLOT (figureWindowShown ()));
+
     // Status bar
     m_statusBar = win->statusBar ();
     int boffset = 0;
@@ -1079,6 +1086,30 @@
   }
 
   void
+  Figure::figureWindowShown ()
+  {
+#if defined (HAVE_QSCREEN_DEVICEPIXELRATIO)
+    figure::properties& fp = properties<figure> ();
+    QMainWindow *win = qWidget<QMainWindow> ();
+    QWindow* window = win->windowHandle ();
+    QScreen* screen = window->screen ();
+    fp.set___device_pixel_ratio__ (screen->devicePixelRatio ());
+
+    connect (window, SIGNAL (screenChanged (QScreen*)),
+             this, SLOT (screenChanged (QScreen*)));
+#endif
+  }
+
+  void
+  Figure::screenChanged (QScreen* screen)
+  {
+#if defined (HAVE_QSCREEN_DEVICEPIXELRATIO)
+    figure::properties& fp = properties<figure> ();
+    fp.set___device_pixel_ratio__ (screen->devicePixelRatio ());
+#endif
+  }
+
+  void
   Figure::enableMouseTracking (void)
   {
     // Enable mouse tracking on every widgets
diff -r 1b1b29705d53 -r f51c8af17df7 libgui/graphics/Figure.h
--- a/libgui/graphics/Figure.h	Mon Apr 09 11:33:21 2018 -0700
+++ b/libgui/graphics/Figure.h	Thu Apr 12 11:38:20 2018 +0200
@@ -32,6 +32,7 @@
 
 class QMainWindow;
 class QToolBar;
+class QScreen;
 
 namespace QtHandles
 {
@@ -128,6 +129,8 @@
     void toggleAxes (void);
     void toggleGrid (void);
     void autoAxes (void);
+    void figureWindowShown ();
+    void screenChanged (QScreen*);
 
   public slots:
     uint8NDArray slotGetPixels (void);
diff -r 1b1b29705d53 -r f51c8af17df7 libgui/graphics/FigureWindow.cc
--- a/libgui/graphics/FigureWindow.cc	Mon Apr 09 11:33:21 2018 -0700
+++ b/libgui/graphics/FigureWindow.cc	Thu Apr 12 11:38:20 2018 +0200
@@ -48,4 +48,10 @@
     return nullptr;
   }
 
+  void FigureWindow::showEvent (QShowEvent* ev)
+  {
+    QMainWindow::showEvent (ev);
+    emit figureWindowShown();
+  }
+
 }
diff -r 1b1b29705d53 -r f51c8af17df7 libgui/graphics/FigureWindow.h
--- a/libgui/graphics/FigureWindow.h	Mon Apr 09 11:33:21 2018 -0700
+++ b/libgui/graphics/FigureWindow.h	Thu Apr 12 11:38:20 2018 +0200
@@ -37,10 +37,17 @@
     Q_OBJECT
 
   public:
-    FigureWindow (QWidget *parent = nullptr);
+    explicit FigureWindow (QWidget *parent = nullptr);
     ~FigureWindow (void);
 
     QMenu * createPopupMenu (void);
+
+  protected:
+    void showEvent(QShowEvent *ev);
+
+  signals:
+    void figureWindowShown();
+
   };
 
 }
diff -r 1b1b29705d53 -r f51c8af17df7 libgui/graphics/GLCanvas.cc
--- a/libgui/graphics/GLCanvas.cc	Mon Apr 09 11:33:21 2018 -0700
+++ b/libgui/graphics/GLCanvas.cc	Thu Apr 12 11:38:20 2018 +0200
@@ -68,7 +68,10 @@
       {
         octave::opengl_renderer r;
 
-        r.set_viewport (width (), height ());
+        graphics_object fig = go.get_ancestor ("figure");
+        double dpr = fig.get ("__device_pixel_ratio__").double_value ();
+
+        r.set_viewport (dpr * width (), dpr * height ());
         r.draw (go);
       }
   }
@@ -173,7 +176,10 @@
       {
         octave::opengl_selector s;
 
-        s.set_viewport (width (), height ());
+        graphics_object fig = ax.get_ancestor ("figure");
+        double dpr = fig.get ("__device_pixel_ratio__").double_value ();
+
+        s.set_viewport (dpr * width (), dpr * height ());
         return s.select (ax, pt.x (), height () - pt.y (),
                          octave::select_ignore_hittest);
       }
diff -r 1b1b29705d53 -r f51c8af17df7 libinterp/corefcn/gl-render.cc
--- a/libinterp/corefcn/gl-render.cc	Mon Apr 09 11:33:21 2018 -0700
+++ b/libinterp/corefcn/gl-render.cc	Thu Apr 12 11:38:20 2018 +0200
@@ -593,7 +593,7 @@
     : toolkit (), xform (), xmin (), xmax (), ymin (), ymax (),
       zmin (), zmax (), xZ1 (), xZ2 (), marker_id (), filled_marker_id (),
       camera_pos (), camera_dir (), interpreter ("none"), txt_renderer (),
-      selecting (false)
+      selecting (false), m_devpixfactor (1.)
   {
     // This constructor will fail if we don't have OpenGL or if the data
     // types we assumed in our public interface aren't compatible with the
@@ -694,8 +694,11 @@
   void
   opengl_renderer::draw_figure (const figure::properties& props)
   {
+    // Current physical-pixel to toolkit-pixel factor
+    m_devpixfactor = props.get___device_pixel_ratio__ ();
+    
     // Initialize OpenGL context
-
+    
     init_gl_context (props.is_graphicssmoothing (), props.get_color_rgb ());
 
 #if defined (HAVE_OPENGL)
@@ -1123,6 +1126,11 @@
     glMultMatrixd (x_mat1.data ());
     glMatrixMode (GL_PROJECTION);
     glLoadIdentity ();
+
+    // Use abstract Octave-pixels for transformation, not physical-pixels
+    vw[2] = octave::math::round (static_cast<float> (vw[2]) / m_devpixfactor);
+    vw[3] = octave::math::round (static_cast<float> (vw[3]) / m_devpixfactor);
+    
     glOrtho (0, vw[2], vw[3], 0, xZ1, xZ2);
     glMultMatrixd (x_mat2.data ());
     glMatrixMode (GL_MODELVIEW);
@@ -3528,6 +3536,10 @@
     glMatrixMode (GL_PROJECTION);
     glPushMatrix ();
     glLoadIdentity ();
+
+    vp[2] = octave::math::round (static_cast<float> (vp[2]) / m_devpixfactor);
+    vp[3] = octave::math::round (static_cast<float> (vp[3]) / m_devpixfactor);
+    
     glOrtho (0, vp[2], vp[3], 0, xZ1, xZ2);
     glMatrixMode (GL_MODELVIEW);
     glPushMatrix ();
@@ -3695,10 +3707,12 @@
         // FIXME: actually add the code to do it!
       }
 
+
     if (i0 >= i1 || j0 >= j1)
       return;
 
-    glPixelZoom (pix_dx, -pix_dy);
+    glPixelZoom (m_devpixfactor * pix_dx,
+                 - m_devpixfactor * pix_dy);
     glRasterPos3d (im_xmin + nor_dx*j0, im_ymin + nor_dy*i0, 0);
 
     // by default this is 4
@@ -3951,7 +3965,7 @@
   {
 #if defined (HAVE_OPENGL)
 
-    glLineWidth (w);
+    glLineWidth (w * m_devpixfactor);
 
 #else
 
@@ -4101,6 +4115,10 @@
     glMatrixMode (GL_PROJECTION);
     glPushMatrix ();
     glLoadIdentity ();
+
+    vw[2] = octave::math::round (static_cast<float> (vw[2]) / m_devpixfactor);
+    vw[3] = octave::math::round (static_cast<float> (vw[3]) / m_devpixfactor);
+    
     glOrtho (0, vw[2], vw[3], 0, xZ1, xZ2);
     glMatrixMode (GL_MODELVIEW);
     glPushMatrix ();
diff -r 1b1b29705d53 -r f51c8af17df7 libinterp/corefcn/gl-render.h
--- a/libinterp/corefcn/gl-render.h	Mon Apr 09 11:33:21 2018 -0700
+++ b/libinterp/corefcn/gl-render.h	Thu Apr 12 11:38:20 2018 +0200
@@ -222,6 +222,9 @@
 
     // Indicate we are drawing for selection purpose
     bool selecting;
+
+    // Factor used for translating Octave pixels to actual device pixels
+    double m_devpixfactor;
   private:
     class patch_tesselator;
   };
diff -r 1b1b29705d53 -r f51c8af17df7 libinterp/corefcn/graphics.cc
--- a/libinterp/corefcn/graphics.cc	Mon Apr 09 11:33:21 2018 -0700
+++ b/libinterp/corefcn/graphics.cc	Thu Apr 12 11:38:20 2018 +0200
@@ -869,6 +869,19 @@
                            sz.extract_n (0, 2, 1, 2)).extract_n (0, 2, 1, 2);
 }
 
+static double
+device_pixel_ratio (graphics_handle h)
+{
+  double retval = 1.0;
+  
+  graphics_object fig = gh_manager::get_object (h).get_ancestor ("figure");
+  
+  if (fig.valid_object ())
+    retval = fig.get ("__device_pixel_ratio__").double_value ();
+  
+  return retval;
+}
+
 static void
 convert_cdata_2 (bool is_scaled, bool is_real, double clim_0, double clim_1,
                  const double *cmapv, double x, octave_idx_type lda,
@@ -6581,11 +6594,13 @@
 
     }
 
+  double dpr = device_pixel_ratio (get___myhandle__ ());
+  
   gh_manager::auto_lock guard;
   txt_renderer.set_font (get ("fontname").string_value (),
                          get ("fontweight").string_value (),
                          get ("fontangle").string_value (),
-                         get ("__fontsize_points__").double_value ());
+                         get ("__fontsize_points__").double_value () * dpr);
 }
 
 // The INTERNAL flag defines whether position or outerposition is used.
@@ -7654,6 +7669,7 @@
 {
   Matrix ext (1, 2, 0.0);
   double wmax, hmax;
+  double dpr = device_pixel_ratio (get___myhandle__ ());
   wmax = hmax = 0.0;
   int n = std::min (ticklabels.numel (), ticks.numel ());
   for (int i = 0; i < n; i++)
@@ -7671,8 +7687,8 @@
               ext = txt_renderer.get_extent (label, 0.0,
                                              get_ticklabelinterpreter ());
 
-              wmax = std::max (wmax, ext(0));
-              hmax = std::max (hmax, ext(1));
+              wmax = std::max (wmax, ext(0) / dpr);
+              hmax = std::max (hmax, ext(1) / dpr);
             }
           else
             {
@@ -8699,7 +8715,14 @@
   m(0) += p(0);
   m(1) += p(1);
 
-  return convert_text_position (m, *this, "pixels", get_units ());
+  Matrix bbox = convert_text_position (m, *this, "pixels", get_units ());
+
+  double dpr = device_pixel_ratio (get___myhandle__ ());
+
+  for (octave_idx_type ii = 0; ii < bbox.numel (); ii++)
+    bbox(ii) = bbox(ii) / dpr;
+  
+  return bbox;
 }
 
 void
@@ -8737,11 +8760,13 @@
 void
 text::properties::update_font (void)
 {
+  double dpr = device_pixel_ratio (get___myhandle__ ());
+
   gh_manager::auto_lock guard;
   txt_renderer.set_font (get ("fontname").string_value (),
                          get ("fontweight").string_value (),
                          get ("fontangle").string_value (),
-                         get ("__fontsize_points__").double_value ());
+                         get ("__fontsize_points__").double_value () * dpr);
 
   txt_renderer.set_color (get_color_rgb ());
 }
@@ -8781,7 +8806,7 @@
   // The bbox is relative to the text's position.  We'll leave it that
   // way, because get_position does not return valid results when the
   // text is first constructed.  Conversion to proper coordinates is
-  // performed in get_extent.
+  // performed in get_extent.  
   set_extent (bbox);
 
   if (__autopos_tag___is ("xlabel") || __autopos_tag___is ("ylabel")
@@ -8838,9 +8863,9 @@
   double fontsz = get_fontsize ();
   double parent_height = box_pix_height;
 
+  graphics_object go (gh_manager::get_object (get___myhandle__ ()));
   if (fontunits_is ("normalized") && parent_height <= 0)
     {
-      graphics_object go (gh_manager::get_object (get___myhandle__ ()));
       graphics_object ax (go.get_ancestor ("axes"));
 
       parent_height = ax.get_properties ().get_boundingbox (true).elem (3);
diff -r 1b1b29705d53 -r f51c8af17df7 libinterp/corefcn/graphics.in.h
--- a/libinterp/corefcn/graphics.in.h	Mon Apr 09 11:33:21 2018 -0700
+++ b/libinterp/corefcn/graphics.in.h	Thu Apr 12 11:38:20 2018 +0200
@@ -3178,6 +3178,7 @@
       any_property __plot_stream__ h , Matrix ()
       any_property __rotate_mode__ h , Matrix ()
       any_property __zoom_mode__ h , Matrix ()
+      double_property __device_pixel_ratio__ h , 1.0
 
       // Obsolete properties: doublebuffer, mincolormap, wvisual, wvisualmode,
       //                      xdisplay, xvisual, xvisualmode
diff -r 1b1b29705d53 -r f51c8af17df7 m4/acinclude.m4
--- a/m4/acinclude.m4	Mon Apr 09 11:33:21 2018 -0700
+++ b/m4/acinclude.m4	Thu Apr 12 11:38:20 2018 +0200
@@ -666,6 +666,36 @@
   fi
 ])
 dnl
+dnl Check whether the Qt class QScreen has the devicePixelRatio member function.
+dnl This member function was introduced in Qt 5.5.
+dnl
+AC_DEFUN([OCTAVE_CHECK_FUNC_QSCREEN_DEVICEPIXELRATIO], [
+  AC_CACHE_CHECK([for QScreen::devicePixelRatio in <QScreen>],
+    [octave_cv_func_qscreen_devicepixelratio],
+    [AC_LANG_PUSH(C++)
+    ac_octave_save_CPPFLAGS="$CPPFLAGS"
+    ac_octave_save_CXXFLAGS="$CXXFLAGS"
+    CPPFLAGS="$QT_CPPFLAGS $CXXPICFLAG $CPPFLAGS"
+    CXXFLAGS="$CXXPICFLAG $CXXFLAGS"
+    AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+        #include <QApplication>
+        #include <QScreen>
+        ]], [[
+        QScreen *screen = QApplication::primaryScreen ();
+        qreal ratio = screen->devicePixelRatio ();
+        ]])],
+      octave_cv_func_qscreen_devicepixelratio=yes,
+      octave_cv_func_qscreen_devicepixelratio=no)
+    CPPFLAGS="$ac_octave_save_CPPFLAGS"
+    CXXFLAGS="$ac_octave_save_CXXFLAGS"
+    AC_LANG_POP(C++)
+  ])
+  if test $octave_cv_func_qscreen_devicepixelratio = yes; then
+    AC_DEFINE(HAVE_QSCREEN_DEVICEPIXELRATIO, 1,
+      [Define to 1 if you have the `QScreen::devicePixelRatio' member function.])
+  fi
+])
+dnl
 dnl Check whether the Qt class QTabWidget has the setMovable member function.
 dnl This member function was introduced in Qt 4.5.
 dnl
@@ -2101,6 +2131,7 @@
     OCTAVE_CHECK_FUNC_QHELPSEARCHQUERYWIDGET_SEARCHINPUT
     OCTAVE_CHECK_FUNC_QINSTALLMESSAGEHANDLER
     OCTAVE_CHECK_FUNC_QLINEEDIT_SETPLACEHOLDERTEXT
+    OCTAVE_CHECK_FUNC_QSCREEN_DEVICEPIXELRATIO
     OCTAVE_CHECK_FUNC_QMOUSEEVENT_LOCALPOS
     OCTAVE_CHECK_FUNC_QOBJECT_FINDCHILDREN_ACCEPTS_FINDCHILDOPTIONS
     OCTAVE_CHECK_FUNC_QTABWIDGET_SETMOVABLE
diff -r 1b1b29705d53 -r f51c8af17df7 scripts/plot/util/print.m
--- a/scripts/plot/util/print.m	Mon Apr 09 11:33:21 2018 -0700
+++ b/scripts/plot/util/print.m	Thu Apr 12 11:38:20 2018 +0200
@@ -376,6 +376,15 @@
       nfig += 1;
     endfor
 
+    ## Don't account for the actual pixel density
+    if (strcmp (tk, "qt"))
+      props(end+1).h = opts.figure;
+      props(end).name = "__device_pixel_ratio__";
+      props(end).value = {get(opts.figure, "__device_pixel_ratio__")};
+      set (opts.figure, "__device_pixel_ratio__", 1);
+      nfig += 1;
+    endif
+
     ## print() requires axes units = "normalized"
     hax = findall (opts.figure, "-depth", 1, "type", "axes", ...
       "-not", "units", "normalized");
