Skip to content

Commit 79c080b

Browse files
committed
Convert internal utilities to pybind11
1 parent e0697d2 commit 79c080b

File tree

2 files changed

+85
-89
lines changed

2 files changed

+85
-89
lines changed

src/_c_internal_utils.cpp

Lines changed: 84 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,23 @@
44
#define WINVER 0x0A00
55
#define _WIN32_WINNT 0x0A00
66
#endif
7-
#define PY_SSIZE_T_CLEAN
8-
#include <Python.h>
7+
#include <pybind11/pybind11.h>
98
#ifdef __linux__
109
#include <dlfcn.h>
1110
#endif
1211
#ifdef _WIN32
1312
#include <Objbase.h>
1413
#include <Shobjidl.h>
1514
#include <Windows.h>
15+
#define UNUSED_ON_NON_WINDOWS(x) x
16+
#else
17+
#define UNUSED_ON_NON_WINDOWS Py_UNUSED
1618
#endif
1719

18-
static PyObject*
19-
mpl_display_is_valid(PyObject* module)
20+
namespace py = pybind11;
21+
22+
static bool
23+
mpl_display_is_valid(void)
2024
{
2125
#ifdef __linux__
2226
void* libX11;
@@ -34,11 +38,10 @@ mpl_display_is_valid(PyObject* module)
3438
XCloseDisplay(display);
3539
}
3640
if (dlclose(libX11)) {
37-
PyErr_SetString(PyExc_RuntimeError, dlerror());
38-
return NULL;
41+
throw std::runtime_error(dlerror());
3942
}
4043
if (display) {
41-
Py_RETURN_TRUE;
44+
return true;
4245
}
4346
}
4447
void* libwayland_client;
@@ -56,84 +59,74 @@ mpl_display_is_valid(PyObject* module)
5659
wl_display_disconnect(display);
5760
}
5861
if (dlclose(libwayland_client)) {
59-
PyErr_SetString(PyExc_RuntimeError, dlerror());
60-
return NULL;
62+
throw std::runtime_error(dlerror());
6163
}
6264
if (display) {
63-
Py_RETURN_TRUE;
65+
return true;
6466
}
6567
}
66-
Py_RETURN_FALSE;
68+
return false;
6769
#else
68-
Py_RETURN_TRUE;
70+
return true;
6971
#endif
7072
}
7173

72-
static PyObject*
73-
mpl_GetCurrentProcessExplicitAppUserModelID(PyObject* module)
74+
static py::object
75+
mpl_GetCurrentProcessExplicitAppUserModelID(void)
7476
{
7577
#ifdef _WIN32
7678
wchar_t* appid = NULL;
7779
HRESULT hr = GetCurrentProcessExplicitAppUserModelID(&appid);
7880
if (FAILED(hr)) {
79-
return PyErr_SetFromWindowsErr(hr);
81+
PyErr_SetFromWindowsErr(hr);
82+
throw py::error_already_set();
8083
}
81-
PyObject* py_appid = PyUnicode_FromWideChar(appid, -1);
84+
auto py_appid = py::cast(appid);
8285
CoTaskMemFree(appid);
8386
return py_appid;
8487
#else
85-
Py_RETURN_NONE;
88+
return py::none();
8689
#endif
8790
}
8891

89-
static PyObject*
90-
mpl_SetCurrentProcessExplicitAppUserModelID(PyObject* module, PyObject* arg)
92+
static void
93+
mpl_SetCurrentProcessExplicitAppUserModelID(const wchar_t* UNUSED_ON_NON_WINDOWS(appid))
9194
{
9295
#ifdef _WIN32
93-
wchar_t* appid = PyUnicode_AsWideCharString(arg, NULL);
94-
if (!appid) {
95-
return NULL;
96-
}
9796
HRESULT hr = SetCurrentProcessExplicitAppUserModelID(appid);
98-
PyMem_Free(appid);
9997
if (FAILED(hr)) {
100-
return PyErr_SetFromWindowsErr(hr);
98+
PyErr_SetFromWindowsErr(hr);
99+
throw py::error_already_set();
101100
}
102-
Py_RETURN_NONE;
103-
#else
104-
Py_RETURN_NONE;
105101
#endif
106102
}
107103

108-
static PyObject*
109-
mpl_GetForegroundWindow(PyObject* module)
104+
static py::object
105+
mpl_GetForegroundWindow(void)
110106
{
111107
#ifdef _WIN32
112-
return PyLong_FromVoidPtr(GetForegroundWindow());
108+
return py::capsule(GetForegroundWindow(), "HWND");
113109
#else
114-
Py_RETURN_NONE;
110+
return py::none();
115111
#endif
116112
}
117113

118-
static PyObject*
119-
mpl_SetForegroundWindow(PyObject* module, PyObject *arg)
114+
static void
115+
mpl_SetForegroundWindow(py::capsule UNUSED_ON_NON_WINDOWS(handle_p))
120116
{
121117
#ifdef _WIN32
122-
HWND handle = PyLong_AsVoidPtr(arg);
123-
if (PyErr_Occurred()) {
124-
return NULL;
125-
}
126-
if (!SetForegroundWindow(handle)) {
127-
return PyErr_Format(PyExc_RuntimeError, "Error setting window");
128-
}
129-
Py_RETURN_NONE;
130-
#else
131-
Py_RETURN_NONE;
118+
if (handle_p.name() != "HWND") {
119+
throw std::runtime_error("Handle must be a value returned from Win32_GetForegroundWindow");
120+
}
121+
HWND handle = static_cast<HWND>(handle_p.get_pointer());
122+
if (!SetForegroundWindow(handle)) {
123+
throw std::runtime_error("Error setting window");
124+
}
132125
#endif
133126
}
134127

135-
static PyObject*
136-
mpl_SetProcessDpiAwareness_max(PyObject* module)
128+
static void
129+
mpl_SetProcessDpiAwareness_max(void)
137130
{
138131
#ifdef _WIN32
139132
#ifdef _DPI_AWARENESS_CONTEXTS_
@@ -171,49 +164,52 @@ mpl_SetProcessDpiAwareness_max(PyObject* module)
171164
SetProcessDPIAware();
172165
#endif
173166
#endif
174-
Py_RETURN_NONE;
175167
}
176168

177-
static PyMethodDef functions[] = {
178-
{"display_is_valid", (PyCFunction)mpl_display_is_valid, METH_NOARGS,
179-
"display_is_valid()\n--\n\n"
180-
"Check whether the current X11 or Wayland display is valid.\n\n"
181-
"On Linux, returns True if either $DISPLAY is set and XOpenDisplay(NULL)\n"
182-
"succeeds, or $WAYLAND_DISPLAY is set and wl_display_connect(NULL)\n"
183-
"succeeds.\n\n"
184-
"On other platforms, always returns True."},
185-
{"Win32_GetCurrentProcessExplicitAppUserModelID",
186-
(PyCFunction)mpl_GetCurrentProcessExplicitAppUserModelID, METH_NOARGS,
187-
"Win32_GetCurrentProcessExplicitAppUserModelID()\n--\n\n"
188-
"Wrapper for Windows's GetCurrentProcessExplicitAppUserModelID.\n\n"
189-
"On non-Windows platforms, always returns None."},
190-
{"Win32_SetCurrentProcessExplicitAppUserModelID",
191-
(PyCFunction)mpl_SetCurrentProcessExplicitAppUserModelID, METH_O,
192-
"Win32_SetCurrentProcessExplicitAppUserModelID(appid, /)\n--\n\n"
193-
"Wrapper for Windows's SetCurrentProcessExplicitAppUserModelID.\n\n"
194-
"On non-Windows platforms, does nothing."},
195-
{"Win32_GetForegroundWindow",
196-
(PyCFunction)mpl_GetForegroundWindow, METH_NOARGS,
197-
"Win32_GetForegroundWindow()\n--\n\n"
198-
"Wrapper for Windows' GetForegroundWindow.\n\n"
199-
"On non-Windows platforms, always returns None."},
200-
{"Win32_SetForegroundWindow",
201-
(PyCFunction)mpl_SetForegroundWindow, METH_O,
202-
"Win32_SetForegroundWindow(hwnd, /)\n--\n\n"
203-
"Wrapper for Windows' SetForegroundWindow.\n\n"
204-
"On non-Windows platforms, does nothing."},
205-
{"Win32_SetProcessDpiAwareness_max",
206-
(PyCFunction)mpl_SetProcessDpiAwareness_max, METH_NOARGS,
207-
"Win32_SetProcessDpiAwareness_max()\n--\n\n"
208-
"Set Windows' process DPI awareness to best option available.\n\n"
209-
"On non-Windows platforms, does nothing."},
210-
{NULL, NULL}}; // sentinel.
211-
static PyModuleDef util_module = {
212-
PyModuleDef_HEAD_INIT, "_c_internal_utils", NULL, 0, functions
213-
};
214-
215-
#pragma GCC visibility push(default)
216-
PyMODINIT_FUNC PyInit__c_internal_utils(void)
169+
PYBIND11_MODULE(_c_internal_utils, m)
217170
{
218-
return PyModule_Create(&util_module);
171+
m.def(
172+
"display_is_valid", &mpl_display_is_valid,
173+
R"""( --
174+
Check whether the current X11 or Wayland display is valid.
175+
176+
On Linux, returns True if either $DISPLAY is set and XOpenDisplay(NULL)
177+
succeeds, or $WAYLAND_DISPLAY is set and wl_display_connect(NULL)
178+
succeeds.
179+
180+
On other platforms, always returns True.)""");
181+
m.def(
182+
"Win32_GetCurrentProcessExplicitAppUserModelID",
183+
&mpl_GetCurrentProcessExplicitAppUserModelID,
184+
R"""( --
185+
Wrapper for Windows's GetCurrentProcessExplicitAppUserModelID.
186+
187+
On non-Windows platforms, always returns None.)""");
188+
m.def(
189+
"Win32_SetCurrentProcessExplicitAppUserModelID",
190+
&mpl_SetCurrentProcessExplicitAppUserModelID,
191+
py::arg("appid"), py::pos_only(),
192+
R"""( --
193+
Wrapper for Windows's SetCurrentProcessExplicitAppUserModelID.
194+
195+
On non-Windows platforms, does nothing.)""");
196+
m.def(
197+
"Win32_GetForegroundWindow", &mpl_GetForegroundWindow,
198+
R"""( --
199+
Wrapper for Windows' GetForegroundWindow.
200+
201+
On non-Windows platforms, always returns None.)""");
202+
m.def(
203+
"Win32_SetForegroundWindow", &mpl_SetForegroundWindow,
204+
py::arg("hwnd"),
205+
R"""( --
206+
Wrapper for Windows' SetForegroundWindow.
207+
208+
On non-Windows platforms, does nothing.)""");
209+
m.def(
210+
"Win32_SetProcessDpiAwareness_max", &mpl_SetProcessDpiAwareness_max,
211+
R"""( --
212+
Set Windows' process DPI awareness to best option available.
213+
214+
On non-Windows platforms, does nothing.)""");
219215
}

src/meson.build

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ extension_data = {
8484
'sources': files(
8585
'_c_internal_utils.cpp',
8686
),
87-
'dependencies': [py3_dep, dl, ole32, shell32, user32],
87+
'dependencies': [pybind11_dep, dl, ole32, shell32, user32],
8888
},
8989
'ft2font': {
9090
'subdir': 'matplotlib',

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy