Skip to content

Commit

Permalink
Set desktop scale factor for external uis if not provided by host
Browse files Browse the repository at this point in the history
  • Loading branch information
falkTX committed Sep 3, 2021
1 parent dbbfef6 commit 37e6922
Showing 1 changed file with 90 additions and 3 deletions.
93 changes: 90 additions & 3 deletions distrho/src/DistrhoUI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,106 @@

#include "DistrhoUIPrivateData.hpp"
#include "src/WindowPrivateData.hpp"
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
# if defined(DISTRHO_OS_HAIKU)
# elif defined(DISTRHO_OS_MAC)
# define Point CocoaPoint
# define Size CocoaSize
# import <Cocoa/Cocoa.h>
# undef Point
# undef Size
# elif defined(DISTRHO_OS_WINDOWS)
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# else
# include <X11/Xresource.h>
# endif
#else
# include "src/TopLevelWidgetPrivateData.hpp"
#endif

START_NAMESPACE_DISTRHO

#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
/* ------------------------------------------------------------------------------------------------------------
* Static data, see DistrhoUIInternal.hpp */

#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
uintptr_t g_nextWindowId = 0;
double g_nextScaleFactor = 1.0;
const char* g_nextBundlePath = nullptr;

/* ------------------------------------------------------------------------------------------------------------
* get global scale factor */

static double getDesktopScaleFactor()
{
// allow custom scale for testing
if (const char* const scale = getenv("DPF_SCALE_FACTOR"))
return std::max(1.0, std::atof(scale));

#if defined(DISTRHO_OS_MAC)
return [NSScreen mainScreen].backingScaleFactor;

This comment has been minimized.

Copy link
@lucianoiam

lucianoiam Sep 3, 2021

Contributor

I don't think it is possible to write Objective-C code in a file with .cpp extension, unless clang is instructed to compile Objective-C++ by changing the extension to .mm . The EmbedExternalUI example builds but my plugin unsurprisingly does not, because the compiler thinks [NSScreen mainScreen] is a C++ capture list. Really don't know why EmbedExternalUI builds, it has to be some coincidence.

Also if you agree I would add a uintptr_t argument to getDesktopScaleFactor() so it is called with the native view handle. In macOS this is useful to query the backing scale factor for that particular view, instead of assuming the view belongs to the main screen. Similarly for Windows to avoid assuming the plugin is visible on the primary monitor.

This comment has been minimized.

Copy link
@falkTX

falkTX Sep 3, 2021

Author Contributor

There is a compiler switch -ObjC++ that takes care of the ObjC support, my bad to assume things were fine.

The point on native pointer is a good one, I was thinking there is no parent to access things from, but that is not true.. this is a plugin after all.
But it is not always the case, standalones wont have the parent window for us to fetch info from..

In any case, need to put this function somewhere else, so the ObjC++ switch is not needed..

This comment has been minimized.

Copy link
@lucianoiam

lucianoiam Sep 3, 2021

Contributor

Didn't know about the switch, yes it would be better to avoid it but comes handy when testing code quickly, thanks.

For the standalone case we can keep assuming the window is displayed on the main screen/monitor, unless ExternalWindow had a method to set that handle somehow, but it is not worth the hassle now. I would push that for the time standalone becomes a fully supported target.

This comment has been minimized.

Copy link
@falkTX

falkTX Sep 3, 2021

Author Contributor

On a 2nd thought, all of dpf/distrho code is always compiled together with the plugin, so we cannot escape the special Obj-C code for this.
I guess a mm file that just links to cpp again, alike pugl.mm->pugl.cpp

This comment has been minimized.

Copy link
@lucianoiam

lucianoiam Sep 3, 2021

Contributor

What about a DistrhoUI.mm that only contains a #include "DistrhoUI.cpp" ? I see a similar trick in DistrhoUI_macOS.mm . Or just put that #include in DistrhoUI_macOS.mm

This comment has been minimized.

Copy link
@falkTX

falkTX Sep 3, 2021

Author Contributor

Ok things should be good on a61cb18 again

This comment has been minimized.

Copy link
@lucianoiam

lucianoiam Sep 3, 2021

Contributor

This is almost perfect now! I tested my own plugin with a resize handle:

  • Mac: Reaper, Live OK
  • Windows: Reaper, Carla OK
  • Linux: Reaper OK. Carla, Bitwig: OK floating window does not resize. Now I recall, I didn't test EmbedExternalUI earlier today on these hosts

Tried to compile EmbedExternalUI, it fails due to X11 Window and DGL::Window colliding. Are you able to compile that example on Linux?

Also, is overriding getNativeWindowHandle() mandatory? REAPER/Linux does not seem to care about it for example, but maybe that is the cause for the broken resize on the others?

This comment has been minimized.

Copy link
@falkTX

falkTX Sep 3, 2021

Author Contributor

Are you able to compile that example on Linux?

I wont be on a linux machine until next week, so no I cannot for now.

Also, is overriding getNativeWindowHandle() mandatory?

Not really, it is used only in LV2 and only on some hosts.
But they tend to behave better if you provide this extra info.

This comment has been minimized.

Copy link
@lucianoiam

lucianoiam Sep 7, 2021

Contributor

We can consider this complete:

  • Build issues fixed by #323
  • EmbedExternalUI resize works for all tested Linux hosts: Reaper, Carla, Bitwig. In addition to the platforms listed above.

This comment has been minimized.

Copy link
@falkTX

falkTX Sep 7, 2021

Author Contributor

Yes, though would be best to find a generic way to find the common scale factory (or scale factor of the primary display) under windows.
I think the current code is wrong.
Still, that can be a separate issue and we can close the main one regarding external ui support.

This comment has been minimized.

Copy link
@lucianoiam

lucianoiam Sep 7, 2021

Contributor

The code displayed below these comments is outdated, latest commits query the scale factor for the plugin window except when it is running standalone I think

? MonitorFromWindow((HWND)parentWindowHandle, MONITOR_DEFAULTTOPRIMARY)

So far I haven't found resizing issues on any host/platform but testing has been always performed on a single monitor setup tbh.

#elif defined(DISTRHO_OS_WINDOWS)
if (const HMODULE Shcore = LoadLibraryA("Shcore.dll"))
{
typedef HRESULT(WINAPI* PFN_GetProcessDpiAwareness)(HANDLE, DWORD*);
typedef HRESULT(WINAPI* PFN_GetScaleFactorForMonitor)(HMONITOR, DWORD*);

const PFN_GetProcessDpiAwareness GetProcessDpiAwareness
= (PFN_GetProcessDpiAwareness)GetProcAddress(Shcore, "GetProcessDpiAwareness");
const PFN_GetScaleFactorForMonitor GetScaleFactorForMonitor
= (PFN_GetScaleFactorForMonitor)GetProcAddress(Shcore, "GetScaleFactorForMonitor");

DWORD dpiAware = 0;
if (GetProcessDpiAwareness && GetScaleFactorForMonitor
&& GetProcessDpiAwareness(NULL, &dpiAware) == 0 && dpiAware != 0)
{
// TODO replace with something else
const HMONITOR hMon = MonitorFromWindow(nullptr, MONITOR_DEFAULTTOPRIMARY);

DWORD scaleFactor = 0;
if (GetScaleFactorForMonitor(hMon, &scaleFactor) == 0 && scaleFactor != 0)
{
FreeLibrary(Shcore);
return static_cast<double>(scaleFactor) / 100.0;
}
}

FreeLibrary(Shcore);
}
#elif defined(HAVE_X11)
::Display* const display = XOpenDisplay(nullptr);
DISTRHO_SAFE_ASSERT_RETURN(display != nullptr, 1.0);

XrmInitialize();

if (char* const rms = XResourceManagerString(view->world->impl->display))
{
if (const XrmDatabase sdb = XrmGetStringDatabase(rms))
{
char* type = nullptr;
XrmValue ret;

if (XrmGetResource(sdb, "Xft.dpi", "String", &type, &ret)
&& ret.addr != nullptr
&& type != nullptr
&& std::strncmp("String", type, 6) == 0)
{
if (const double dpi = std::atof(ret.addr))
{
XCloseDisplay(display);
return dpi / 96;
}
}
}
}

XCloseDisplay(display);
#endif

return 1.0;
}

#endif

/* ------------------------------------------------------------------------------------------------------------
Expand All @@ -50,7 +137,7 @@ UI::PrivateData::createNextWindow(UI* const ui, const uint width, const uint hei
ewData.parentWindowHandle = pData->winId;
ewData.width = width;
ewData.height = height;
ewData.scaleFactor = pData->scaleFactor;
ewData.scaleFactor = pData->scaleFactor != 0.0 ? pData->scaleFactor : getDesktopScaleFactor();
ewData.title = DISTRHO_PLUGIN_NAME;
ewData.isStandalone = DISTRHO_UI_IS_STANDALONE;
return ewData;
Expand Down

0 comments on commit 37e6922

Please sign in to comment.