Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The case for Fl_Window::pixels_per_unit() and Fl_Double_Window::pixels_per_unit() #230

Closed
parasyte opened this issue May 8, 2021 · 1 comment

Comments

@parasyte
Copy link

parasyte commented May 8, 2021

This function exists on Fl_Gl_Window and the os-issues documentation has some information on this method:

The Fl_Gl_Window::pixels_per_unit() method is useful when the OpenGL code depends on the pixel dimension
of the GL scene. This occurs, e.g., if a window's handle() method uses Fl::event_x() and Fl::event_y()
whose returned values should be multiplied by Fl_Gl_Window::pixels_per_unit() to obtain the adequate pixel units.
This method may also be useful, for example, to adjust the width of a line in a high resolution GL scene.

At least on macOS, it appears that Fl_Double_Window needs this same method for windows with a CAMetalLayer.

The XY problem goes like this: I don't need a GL window because I'm not using OpenGL. I am using Metal. A double-buffered window works well for this, except Metal and "Retina" displays have the same issues as described in the doc:

\subsection osissues_retina OpenGL and 'retina' displays
It is possible to have OpenGL produce graphics at the high pixel resolution allowed by the so-called 'retina' displays
present on recent Apple hardware.
For this, call
\verbatim
Fl::use_high_res_GL(1);
\endverbatim
before any Fl_Gl_Window is shown. Also, adapt your Fl_Gl_Window::draw() and Fl_Gl_Window::draw_overlay() methods replacing
\verbatim
glViewport(0, 0, w(), h());
\endverbatim
by
\verbatim
glViewport(0, 0, pixel_w(), pixel_h());
\endverbatim
making use of the Fl_Gl_Window::pixel_w() and Fl_Gl_Window::pixel_h() methods that return the width and height of
the GL scene in pixels: if the Fl_Gl_Window is mapped on a retina display, these methods return twice as much as
reported by Fl_Widget::w() and Fl_Widget::h(); if it's mapped on a regular display, they return the same values
as w() and h(). These methods dynamically change their values if the window is moved into/out from a retina
display. If Fl::use_high_res_GL(1) is not called, all Fl_Gl_Window 's are drawn at low resolution.
These methods are useful on all platforms because Fl_Gl_Window::w() and Fl_Gl_Window::h() don't return,
on HighDPI displays, the quantitites in pixels necessary to OpenGL functions .

Gaining access to the scaling factor (and the pixel width/height as explained in docs) for Metal layers on non-GL windows would be very helpful for all the same reasons.

The same doc also describes that Fl_Window and Fl_Double_Window act identically on macOS:

\subsection double_window Fl_Double_Window
OS X double-buffers all windows automatically. On OS X, Fl_Window and Fl_Double_Window are handled
internally in the same way.


FWIW, I have attempted to use Fl_Gl_Window with Metal, but it prints this message:

2021-05-08 14:52:24.555 minimal-fltk[88155:717115] CoreAnimation: setting `contents' on CAMetalLayer may result in undefined behavior

I don't know the details here, but it looks like a conflict between the Fl_Gl_Window cocoa driver and my graphics stack which uses CAMetalLayer. So I'm ruling out Fl_Gl_Window as useful in my situation. It does support pixels_per_unit() though, and it also returns the expected scale factor that the app needs.

My other alternative is always assuming the scaling factor is 2. Works great on my MacBook Pro, but not so much on other platforms...

@ManoloFLTK
Copy link
Contributor

This issue seems specific to the macOS platform of FLTK since Metal is involved.
Therefore, adding in your code a small bit of Objective-c should be a working solution.

Here is a suggestion:
starting from your Fl_Window * object (which can also be an Fl_Double_Window), say win,
NSView *view = [fl_xid(win) contentView];
will give you the NSView object, view, corresponding to this window,
NSSize s = [view convertSizeToBacking:NSMakeSize(10, 10)];
int scale = (int(s.width + 0.5) > 10 ? 2 : 1);
will give you the correct scale factor for your window, 2 if it's on a retina display,
1 if it's not.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants