Thanks to visit codestin.com
Credit goes to github.com

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)