From: FX (
Date: Sat Dec 07 2019 - 11:12:27 CST

> Remaining issue: VMD is working in low-resolution on “Retina” displays. This affects the OpenGL window, as well as all interface elements (menus, text, etc.). This is particularly difficult for extension windows, whose text is smaller and where the low-res version is hard to read.

Documenting further progress: I can enable Retina display (in the app’s Info.plist), and it works for UI elements and extensions. However, if I do this, the OpenGL viewport is wrongly set, and the OpenGL display only occupies one quarter (half heigh, half width) of the VMD window. This appears documented well in the FLTK documentation:

Following the instructions there, and compiling with FLTK 1.4 20019-11-22 and Tcl/Tk 8.6.9, I can get a fully high-resolution version of VMD working with a simple patch (see below). What is needed is:

For the code in FltkOpenGLDisplayDevice.C:
- calling Fl::use_high_res_GL very early
- using Fl_Gl_Window::pixel_w (and Fl_Gl_Window::pixel_h) instead of Fl::w (and Fl::h)
- where Fl::event_x_root (and Fl::event_y_root) are called, multiply the result by window->pixels_per_unit()
- same for window->x() and window->y()

For the two Info.plist files inside the app bundle:
- set the NSHighResolutionCapable key to be true
- remove and reinstall the modified .app bundle, as macOS will not read this Info.plist time every time, but instead caches the app’s capabilities
(finding this out took me some time, as you can imagine...)

For Tcl/Tk 8.6.9:
- nothing! Having the NSHighResolutionCapable key in Info.plist makes it work

I have only tested it lightly so far, but the following works:
 - displaying objects in the OpenGL window
 - using mouse operations to rotate, scale, translate, center, etc.
 - query atoms, label atoms, bonds, angles, etc.
 - window resizing (almost: see below)

There is only one tiny glitch, which is not actually linked to enabling Retina display, I am seeing it also with a non-retina 64-bit build. During and after window resizing, the OpenGL is not redrawn. The OpenGL window becomes bright red, and will stay that way. Any further change in the viewpoint (rotate, translate, scale, etc.) will redraw the content fine, and the new window size is taken into account. So I think it’s just missing a redraw / needredraw somewhere, should be easy to fix.

I am interested in knowing what are the other things you think may be useful to test. (I am using VMD regularly, but only for some basic features).

Best regards,


diff -pur vmd-1.9.4a38-orig/vmd-1.9.4a38/src/FltkOpenGLDisplayDevice.C vmd-1.9.4a38/vmd-1.9.4a38/src/FltkOpenGLDisplayDevice.C
--- vmd-1.9.4a38-orig/vmd-1.9.4a38/src/FltkOpenGLDisplayDevice.C 2019-10-17 18:11:23.000000000 +0200
+++ vmd-1.9.4a38/vmd-1.9.4a38/src/FltkOpenGLDisplayDevice.C 2019-12-07 17:48:48.000000000 +0100
@@ -202,6 +202,10 @@ FltkOpenGLDisplayDevice::FltkOpenGLDispl
   cacheNames = glCacheNameStr;
   cacheModes = OPENGL_CACHE_MODES;
+#ifdef __APPLE__
+ Fl::use_high_res_GL(1);
   // open the window
   int SX = 100, SY = 100, W, H;
@@ -249,8 +253,8 @@ FltkOpenGLDisplayDevice::FltkOpenGLDispl
   // (8) actually request the window to be displayed
- screenX = Fl::w();
- screenY = Fl::h();
+ screenX = window->pixel_w();
+ screenY = window->pixel_h();
   // (9) configure the rendering properly
   setup_initial_opengl_state(); // setup initial OpenGL state
@@ -303,7 +307,7 @@ FltkOpenGLDisplayDevice::~FltkOpenGLDisp
 int FltkOpenGLDisplayDevice::x(void) {
 #if 1
- return Fl::event_x_root();
+ return Fl::event_x_root() * window->pixels_per_unit();
   int x, y;
   Fl::get_mouse(x, y);
@@ -316,7 +320,7 @@ int FltkOpenGLDisplayDevice::x(void) {
 int FltkOpenGLDisplayDevice::y(void) {
 #if 1
- return screenY - Fl::event_y_root();
+ return screenY - Fl::event_y_root() * window->pixels_per_unit();
   int x, y;
   Fl::get_mouse(x, y);
@@ -443,10 +447,10 @@ int FltkOpenGLDisplayDevice::read_event(
 // reshape the display after a shape change
 void FltkOpenGLDisplayDevice::reshape(void) {
- xSize = window->w();
- ySize = window->h();
- xOrig = window->x();
- yOrig = screenY - window->y() - ySize;
+ xSize = window->pixel_w();
+ ySize = window->pixel_h();
+ xOrig = window->x() * window->pixels_per_unit();
+ yOrig = screenY - window->y() * window->pixels_per_unit() - ySize;
   switch (inStereo) {