diff --git a/libgui/graphics/Figure.cc b/libgui/graphics/Figure.cc
--- a/libgui/graphics/Figure.cc
+++ b/libgui/graphics/Figure.cc
@@ -41,6 +41,8 @@ along with Octave; see the file COPYING.
 #include <QtDebug>
 #include <QTimer>
 #include <QToolBar>
+#include <QWindow>
+#include <QScreen>
 
 #include "Canvas.h"
 #include "Container.h"
@@ -133,6 +135,11 @@ namespace QtHandles
 
     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,32 @@ namespace QtHandles
   }
 
   void
+  Figure::figureWindowShown ()
+  {
+    figure::properties& fp = properties<figure> ();
+    QMainWindow *win = qWidget<QMainWindow> ();
+#if defined (HAVE_QSCREEN_DEVICEPIXELRATIO)
+    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)
+  {
+    figure::properties& fp = properties<figure> ();
+
+ #if defined (HAVE_QSCREEN_DEVICEPIXELRATIO)
+    fp.set___device_pixel_ratio__ (screen->devicePixelRatio ());
+ #endif
+  }
+
+  void
   Figure::enableMouseTracking (void)
   {
     // Enable mouse tracking on every widgets
diff --git a/libgui/graphics/Figure.h b/libgui/graphics/Figure.h
--- a/libgui/graphics/Figure.h
+++ b/libgui/graphics/Figure.h
@@ -32,6 +32,7 @@ along with Octave; see the file COPYING.
 
 class QMainWindow;
 class QToolBar;
+class QScreen;
 
 namespace QtHandles
 {
@@ -128,6 +129,8 @@ namespace QtHandles
     void toggleAxes (void);
     void toggleGrid (void);
     void autoAxes (void);
+    void figureWindowShown ();
+    void screenChanged (QScreen*);
 
   public slots:
     uint8NDArray slotGetPixels (void);
diff --git a/libgui/graphics/FigureWindow.cc b/libgui/graphics/FigureWindow.cc
--- a/libgui/graphics/FigureWindow.cc
+++ b/libgui/graphics/FigureWindow.cc
@@ -48,4 +48,10 @@ namespace QtHandles
     return nullptr;
   }
 
+  void FigureWindow::showEvent (QShowEvent* ev)
+  {
+    QMainWindow::showEvent (ev);
+    emit figureWindowShown();
+  }
+
 }
diff --git a/libgui/graphics/FigureWindow.h b/libgui/graphics/FigureWindow.h
--- a/libgui/graphics/FigureWindow.h
+++ b/libgui/graphics/FigureWindow.h
@@ -37,10 +37,17 @@ namespace QtHandles
     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 --git a/libgui/graphics/GLCanvas.cc b/libgui/graphics/GLCanvas.cc
--- a/libgui/graphics/GLCanvas.cc
+++ b/libgui/graphics/GLCanvas.cc
@@ -68,7 +68,12 @@ namespace QtHandles
       {
         octave::opengl_renderer r;
 
-        r.set_viewport (width (), height ());
+ graphics_object fig = go.get_ancestor ("figure");
+ const figure::properties& fp =
+   dynamic_cast<const figure::properties&> (fig.get_properties ());
+ double devicePixelRatio = fp.get___device_pixel_ratio__ ();
+
+        r.set_viewport (devicePixelRatio * width (), devicePixelRatio * height ());
         r.draw (go);
       }
   }
@@ -173,7 +178,12 @@ namespace QtHandles
       {
         octave::opengl_selector s;
 
-        s.set_viewport (width (), height ());
+        graphics_object fig = ax.get_ancestor ("figure");
+        const figure::properties& fp =
+        dynamic_cast<const figure::properties&> (fig.get_properties ());
+        double devicePixelRatio = fp.get___device_pixel_ratio__ ();
+
+        s.set_viewport (devicePixelRatio * width (), devicePixelRatio * height ());
         return s.select (ax, pt.x (), height () - pt.y (),
                          octave::select_ignore_hittest);
       }
diff --git a/libgui/graphics/gl-select.cc b/libgui/graphics/gl-select.cc
--- a/libgui/graphics/gl-select.cc
+++ b/libgui/graphics/gl-select.cc
@@ -54,9 +54,10 @@ namespace octave
   }
 
   void
-  opengl_selector::init_marker (const std::string& m, double sz, float width)
+  opengl_selector::init_marker (const std::string& m, double sz, float width,
+    double devicePixelRatio)
   {
-    opengl_renderer::init_marker (m, sz, width);
+    opengl_renderer::init_marker (m, sz, width, devicePixelRatio);
     apply_pick_matrix ();
   }
 
diff --git a/libgui/graphics/gl-select.h b/libgui/graphics/gl-select.h
--- a/libgui/graphics/gl-select.h
+++ b/libgui/graphics/gl-select.h
@@ -56,7 +56,8 @@ namespace octave
 
     virtual void setup_opengl_transformation (const axes::properties& props);
 
-    virtual void init_marker (const std::string& m, double size, float width);
+    virtual void init_marker (const std::string& m, double size, float width,
+      double devicePixelRatio);
 
     virtual Matrix render_text (const std::string& txt,
                                 double x, double y, double z,
diff --git a/libinterp/corefcn/gl-render.cc b/libinterp/corefcn/gl-render.cc
--- a/libinterp/corefcn/gl-render.cc
+++ b/libinterp/corefcn/gl-render.cc
@@ -1123,6 +1123,11 @@ namespace octave
     glMultMatrixd (x_mat1.data ());
     glMatrixMode (GL_PROJECTION);
     glLoadIdentity ();
+
+    vw[2] = octave::math::round (static_cast<float> (vw[2]) /
+      devicePixelRatio (props));
+    vw[3] = octave::math::round (static_cast<float> (vw[3]) /
+      devicePixelRatio (props));
     glOrtho (0, vw[2], vw[3], 0, xZ1, xZ2);
     glMultMatrixd (x_mat2.data ());
     glMatrixMode (GL_MODELVIEW);
@@ -2274,7 +2279,8 @@ namespace octave
           fc = props.get_markerfacecolor_rgb ();
 
         init_marker (props.get_marker (), props.get_markersize (),
-                     props.get_linewidth ());
+                     props.get_linewidth (),
+                     devicePixelRatio (props));
 
         for (int i = 0; i < n; i++)
           {
@@ -2874,7 +2880,8 @@ namespace octave
           c = props.get_color_data ().array_value ();
 
         init_marker (props.get_marker (), props.get_markersize (),
-                     props.get_linewidth ());
+                     props.get_linewidth (),
+                     devicePixelRatio (props));
 
         for (int i = 0; i < zc; i++)
           {
@@ -3365,7 +3372,8 @@ namespace octave
           }
 
         init_marker (props.get_marker (), props.get_markersize (),
-                     props.get_linewidth ());
+                     props.get_linewidth (),
+                     devicePixelRatio (props));
 
         for (int i = 0; i < nf; i++)
           for (int j = 0; j < count_f(i); j++)
@@ -3528,6 +3536,11 @@ namespace octave
     glMatrixMode (GL_PROJECTION);
     glPushMatrix ();
     glLoadIdentity ();
+
+    vp[2] = octave::math::round (static_cast<float> (vp[2]) /
+                                 devicePixelRatio (props));
+    vp[3] = octave::math::round (static_cast<float> (vp[3]) /
+                                 devicePixelRatio (props));
     glOrtho (0, vp[2], vp[3], 0, xZ1, xZ2);
     glMatrixMode (GL_MODELVIEW);
     glPushMatrix ();
@@ -3695,10 +3708,12 @@ namespace octave
         // FIXME: actually add the code to do it!
       }
 
+
     if (i0 >= i1 || j0 >= j1)
       return;
 
-    glPixelZoom (pix_dx, -pix_dy);
+    glPixelZoom (devicePixelRatio (props) * pix_dx,
+                 -devicePixelRatio (props) * pix_dy);
     glRasterPos3d (im_xmin + nor_dx*j0, im_ymin + nor_dy*i0, 0);
 
     // by default this is 4
@@ -3913,6 +3928,7 @@ namespace octave
     txt_renderer.set_font (props.get ("fontname").string_value (),
                            props.get ("fontweight").string_value (),
                            props.get ("fontangle").string_value (),
+                           devicePixelRatio (props) *
                            props.get ("__fontsize_points__").double_value ());
   }
 
@@ -4086,7 +4102,7 @@ namespace octave
   }
 
   void
-  opengl_renderer::init_marker (const std::string& m, double size, float width)
+  opengl_renderer::init_marker (const std::string& m, double size, float width, double devicePixelRatio)
   {
 #if defined (HAVE_OPENGL)
 
@@ -4101,6 +4117,11 @@ namespace octave
     glMatrixMode (GL_PROJECTION);
     glPushMatrix ();
     glLoadIdentity ();
+
+    vw[2] = octave::math::round (static_cast<float> (vw[2]) /
+                                 devicePixelRatio);
+    vw[3] = octave::math::round (static_cast<float> (vw[3]) /
+                                 devicePixelRatio);
     glOrtho (0, vw[2], vw[3], 0, xZ1, xZ2);
     glMatrixMode (GL_MODELVIEW);
     glPushMatrix ();
diff --git a/libinterp/corefcn/gl-render.h b/libinterp/corefcn/gl-render.h
--- a/libinterp/corefcn/gl-render.h
+++ b/libinterp/corefcn/gl-render.h
@@ -67,6 +67,25 @@ namespace octave
 
     virtual void finish (void);
 
+    virtual double devicePixelRatio (const graphics_object* go)
+    {
+      graphics_object fig = go->get_ancestor ("figure");
+      const figure::properties& fp =
+        dynamic_cast<const figure::properties&> (fig.get_properties ());
+      double devicePixelRatio = fp.get___device_pixel_ratio__ ();
+      return devicePixelRatio;
+    }
+
+    virtual double devicePixelRatio (const base_properties& props)
+    {
+      graphics_object go = gh_manager::get_object (props.get___myhandle__ ());
+      graphics_object fig = go.get_ancestor ("figure");
+      const figure::properties& fp =
+        dynamic_cast<const figure::properties&> (fig.get_properties ());
+      double devicePixelRatio = fp.get___device_pixel_ratio__ ();
+      return devicePixelRatio;
+    }
+
   protected:
     virtual void draw_figure (const figure::properties& props);
     virtual void draw_axes (const axes::properties& props);
@@ -106,7 +125,7 @@ namespace octave
       selecting = on;
     }
 
-    virtual void init_marker (const std::string& m, double size, float width);
+    virtual void init_marker (const std::string& m, double size, float width, double devicePixelRatio);
     virtual void end_marker (void);
     virtual void draw_marker (double x, double y, double z,
                               const Matrix& lc, const Matrix& fc);
diff --git a/libinterp/corefcn/gl2ps-print.cc b/libinterp/corefcn/gl2ps-print.cc
--- a/libinterp/corefcn/gl2ps-print.cc
+++ b/libinterp/corefcn/gl2ps-print.cc
@@ -177,9 +177,10 @@ namespace octave
     void draw_pixels (int w, int h, const uint8_t *data);
     void draw_pixels (int w, int h, const uint16_t *data);
 
-    void init_marker (const std::string& m, double size, float width)
+    void init_marker (const std::string& m, double size, float width,
+      double devicePixelRatio)
     {
-      opengl_renderer::init_marker (m, size, width);
+      opengl_renderer::init_marker (m, size, width, devicePixelRatio);
 
       // FIXME: gl2ps can't handle closed contours and we set linecap/linejoin
       //        round to obtain a better looking result for some markers.
diff --git a/libinterp/corefcn/graphics.cc b/libinterp/corefcn/graphics.cc
--- a/libinterp/corefcn/graphics.cc
+++ b/libinterp/corefcn/graphics.cc
@@ -6581,10 +6581,24 @@ axes::properties::update_font (std::stri
 
     }
 
+  double devicePixelRatio = 1.0;
+  graphics_object go (gh_manager::get_object (get___myhandle__ ()));
+  if (go.valid_object ())
+    {
+      graphics_object fig = go.get_ancestor ("figure");
+      if (fig.valid_object ())
+        {
+          const figure::properties& fp =
+            dynamic_cast<const figure::properties&> (fig.get_properties ());
+          devicePixelRatio = fp.get___device_pixel_ratio__ ();
+        }
+    }
+
   gh_manager::auto_lock guard;
   txt_renderer.set_font (get ("fontname").string_value (),
                          get ("fontweight").string_value (),
                          get ("fontangle").string_value (),
+                         devicePixelRatio *
                          get ("__fontsize_points__").double_value ());
 }
 
@@ -8737,10 +8751,25 @@ text::properties::update_fontunits (cons
 void
 text::properties::update_font (void)
 {
+  graphics_object go (gh_manager::get_object (get___myhandle__ ()));
+
+  double devicePixelRatio = 1.0;
+  if (go.valid_object ())
+    {
+      graphics_object fig = go.get_ancestor ("figure");
+      if (fig.valid_object ())
+        {
+          const figure::properties& fp =
+          dynamic_cast<const figure::properties&> (fig.get_properties ());
+          devicePixelRatio = fp.get___device_pixel_ratio__ ();
+        }
+    }
+
   gh_manager::auto_lock guard;
   txt_renderer.set_font (get ("fontname").string_value (),
                          get ("fontweight").string_value (),
                          get ("fontangle").string_value (),
+                         devicePixelRatio *
                          get ("__fontsize_points__").double_value ());
 
   txt_renderer.set_color (get_color_rgb ());
diff --git a/libinterp/corefcn/graphics.in.h b/libinterp/corefcn/graphics.in.h
--- a/libinterp/corefcn/graphics.in.h
+++ b/libinterp/corefcn/graphics.in.h
@@ -3178,6 +3178,7 @@ public:
       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 --git a/m4/acinclude.m4 b/m4/acinclude.m4
--- a/m4/acinclude.m4
+++ b/m4/acinclude.m4
@@ -666,6 +666,36 @@ AC_DEFUN([OCTAVE_CHECK_FUNC_QOBJECT_FIND
   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
@@ -2127,6 +2157,7 @@ AC_DEFUN([OCTAVE_CHECK_QT_VERSION], [AC_
     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
