[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/larsoner/matplotlib/docstrings/src/_c_internal_utils.cpp [Back]  [Original]

#include 
/* Python.h must be included before any system headers,
    to ensure visibility macros are properly set. */
#include 

#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
// Windows 10, for latest HiDPI API support.
#define WINVER 0x0A00
#if defined(_WIN32_WINNT)
#if _WIN32_WINNT < WINVER
#undef _WIN32_WINNT
#define _WIN32_WINNT WINVER
#endif
#else
#define _WIN32_WINNT WINVER
#endif
#endif
#include 
#ifdef __linux__
#include 
#endif
#ifdef _WIN32
#include 
#include 
#include 
#define UNUSED_ON_NON_WINDOWS(x) x
#else
#define UNUSED_ON_NON_WINDOWS Py_UNUSED
#endif
#ifdef __APPLE__
#include 
#include 
#include 
#endif

namespace py = pybind11;
using namespace pybind11::literals;

static bool
mpl_xdisplay_is_valid(void)
{
#ifdef __linux__
    void* libX11;
    // The getenv check is redundant but helps performance as it is much faster
    // than dlopen().
    if (getenv("DISPLAY")
        && (libX11 = dlopen("libX11.so.6", RTLD_LAZY))) {
        struct Display* display = nullptr;
        auto XOpenDisplay = (struct Display* (*)(char const*))
            dlsym(libX11, "XOpenDisplay");
        auto XCloseDisplay = (int (*)(struct Display*))
            dlsym(libX11, "XCloseDisplay");
        if (XOpenDisplay && XCloseDisplay
                && (display = XOpenDisplay(nullptr))) {
            XCloseDisplay(display);
        }
        if (dlclose(libX11)) {
            throw std::runtime_error(dlerror());
        }
        if (display) {
            return true;
        }
    }
    return false;
#else
    return true;
#endif
}

static bool
mpl_display_is_valid(void)
{
#ifdef __linux__
    if (mpl_xdisplay_is_valid()) {
        return true;
    }
    void* libwayland_client;
    if (getenv("WAYLAND_DISPLAY")
        && (libwayland_client = dlopen("libwayland-client.so.0", RTLD_LAZY))) {
        struct wl_display* display = nullptr;
        auto wl_display_connect = (struct wl_display* (*)(char const*))
            dlsym(libwayland_client, "wl_display_connect");
        auto wl_display_disconnect = (void (*)(struct wl_display*))
            dlsym(libwayland_client, "wl_display_disconnect");
        if (wl_display_connect && wl_display_disconnect
                && (display = wl_display_connect(nullptr))) {
            wl_display_disconnect(display);
        }
        if (dlclose(libwayland_client)) {
            throw std::runtime_error(dlerror());
        }
        if (display) {
            return true;
        }
    }
    return false;
#else
    return true;
#endif
}

static py::object
mpl_get_available_fonts(void)
{
#if defined(__APPLE__)
    py::set fonts;

    // Using CoreText before AppKit is loaded exposes a bug in NSFontCTFont
    // toll-free bridging. Load AppKit now to avoid a future exception.
    dlopen("/System/Library/Frameworks/AppKit.framework/AppKit", RTLD_NOW);

    auto cfStringToPyStr = [](CFStringRef str) -> py::str {
        auto cstr = CFStringGetCStringPtr(str, kCFStringEncodingUTF8);
        if (cstr) {
            return py::str(cstr);
        }
        auto length = CFStringGetLength(str);
        auto maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1;
        auto buffer = std::make_unique(maxSize);
        py::str result;
        if (CFStringGetCString(str, buffer.get(), maxSize, kCFStringEncodingUTF8)) {
            result = py::str(buffer.get());
        }
        return result;
    };

    auto collection = CTFontCollectionCreateFromAvailableFonts(NULL);
    auto descriptors = collection ?
        CTFontCollectionCreateMatchingFontDescriptors(collection) : NULL;
    auto count = descriptors ? CFArrayGetCount(descriptors) : 0;
    for (CFIndex i = 0; i < count; i++) {
        auto descriptor = static_cast(
            CFArrayGetValueAtIndex(descriptors, i));
        auto url = static_cast(
            CTFontDescriptorCopyAttribute(descriptor, kCTFontURLAttribute));
        CFStringRef path = nullptr;
        if (url) {
            path = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
            CFRelease(url);
        }
        if (path) {
            auto pyStr = cfStringToPyStr(path);
            if (pyStr) {
                fonts.add(pyStr);
            }
            CFRelease(path);
        }
    }
    if (descriptors) {
        CFRelease(descriptors);
    }
    if (collection) {
        CFRelease(collection);
    }
    return fonts;
#else
    return py::none();
#endif
}

static py::object
mpl_GetCurrentProcessExplicitAppUserModelID(void)
{
#ifdef _WIN32
    wchar_t* appid = NULL;
    HRESULT hr = GetCurrentProcessExplicitAppUserModelID(&appid);
    if (FAILED(hr)) {
        PyErr_SetFromWindowsErr(hr);
        throw py::error_already_set();
    }
    auto py_appid = py::cast(appid);
    CoTaskMemFree(appid);
    return py_appid;
#else
    return py::none();
#endif
}

static void
mpl_SetCurrentProcessExplicitAppUserModelID(const wchar_t* UNUSED_ON_NON_WINDOWS(appid))
{
#ifdef _WIN32
    HRESULT hr = SetCurrentProcessExplicitAppUserModelID(appid);
    if (FAILED(hr)) {
        PyErr_SetFromWindowsErr(hr);
        throw py::error_already_set();
    }
#endif
}

static py::object
mpl_GetForegroundWindow(void)
{
#ifdef _WIN32
  if (HWND hwnd = GetForegroundWindow()) {
    return py::capsule(hwnd, "HWND");
  } else {
    return py::none();
  }
#else
  return py::none();
#endif
}

static void
mpl_SetForegroundWindow(py::capsule UNUSED_ON_NON_WINDOWS(handle_p))
{
#ifdef _WIN32
    if (strcmp(handle_p.name(), "HWND") != 0) {
        throw std::runtime_error("Handle must be a value returned from Win32_GetForegroundWindow");
    }
    HWND handle = static_cast(handle_p.get_pointer());
    if (!SetForegroundWindow(handle)) {
        throw std::runtime_error("Error setting window");
    }
#endif
}

static void
mpl_SetProcessDpiAwareness_max(void)
{
#ifdef _WIN32
#ifdef _DPI_AWARENESS_CONTEXTS_
    // These functions and options were added in later Windows 10 updates, so
    // must be loaded dynamically.
    HMODULE user32 = LoadLibrary("user32.dll");
    auto IsValidDpiAwarenessContext = (BOOL (WINAPI *)(DPI_AWARENESS_CONTEXT))
        GetProcAddress(user32, "IsValidDpiAwarenessContext");
    auto SetProcessDpiAwarenessContext = (BOOL (WINAPI *)(DPI_AWARENESS_CONTEXT))
        GetProcAddress(user32, "SetProcessDpiAwarenessContext");
    DPI_AWARENESS_CONTEXT ctxs[3] = {
        DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2,  // Win10 Creators Update
        DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE,     // Win10
        DPI_AWARENESS_CONTEXT_SYSTEM_AWARE};         // Win10
    if (IsValidDpiAwarenessContext && SetProcessDpiAwarenessContext) {
        for (size_t i = 0; i < sizeof(ctxs) / sizeof(DPI_AWARENESS_CONTEXT); ++i) {
            if (IsValidDpiAwarenessContext(ctxs[i])) {
                SetProcessDpiAwarenessContext(ctxs[i]);
                break;
            }
        }
    } else {
        // Added in Windows Vista.
        SetProcessDPIAware();
    }
    FreeLibrary(user32);
#else
    // Added in Windows Vista.
    SetProcessDPIAware();
#endif
#endif
}

PYBIND11_MODULE(_c_internal_utils, m, py::mod_gil_not_used())
{
    m.def(
        "display_is_valid", &mpl_display_is_valid,
        R"""(        --
        Check whether the current X11 or Wayland display is valid.

        On Linux, returns True if either $DISPLAY is set and XOpenDisplay(NULL)
        succeeds, or $WAYLAND_DISPLAY is set and wl_display_connect(NULL)
        succeeds.

        On other platforms, always returns True.)""");
    m.def(
        "xdisplay_is_valid", &mpl_xdisplay_is_valid,
        R"""(        --
        Check whether the current X11 display is valid.

        On Linux, returns True if either $DISPLAY is set and XOpenDisplay(NULL)
        succeeds. Use this function if you need to specifically check for X11
        only (e.g., for Tkinter).

        On other platforms, always returns True.)""");
    m.def(
        "get_available_fonts", &mpl_get_available_fonts,
        R"""(        --
        On macOS, uses CoreText to find all fonts available to the current
        process and returns the paths as a set of strings.

        On other platforms, always returns None.)""");
    m.def(
        "Win32_GetCurrentProcessExplicitAppUserModelID",
        &mpl_GetCurrentProcessExplicitAppUserModelID,
        R"""(        --
        Wrapper for Windows's GetCurrentProcessExplicitAppUserModelID.

        On non-Windows platforms, always returns None.)""");
    m.def(
        "Win32_SetCurrentProcessExplicitAppUserModelID",
        &mpl_SetCurrentProcessExplicitAppUserModelID,
        "appid"_a, py::pos_only(),
        R"""(        --
        Wrapper for Windows's SetCurrentProcessExplicitAppUserModelID.

        On non-Windows platforms, does nothing.)""");
    m.def(
        "Win32_GetForegroundWindow", &mpl_GetForegroundWindow,
        R"""(        --
        Wrapper for Windows' GetForegroundWindow.

        On non-Windows platforms, always returns None.)""");
    m.def(
        "Win32_SetForegroundWindow", &mpl_SetForegroundWindow,
        "hwnd"_a,
        R"""(        --
        Wrapper for Windows' SetForegroundWindow.

        On non-Windows platforms, does nothing.)""");
    m.def(
        "Win32_SetProcessDpiAwareness_max", &mpl_SetProcessDpiAwareness_max,
        R"""(        --
        Set Windows' process DPI awareness to best option available.

        On non-Windows platforms, does nothing.)""");
}

Web Proxy Viewer  |  New URL  |  Original Page