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

Skip to content

Commit f33f6cf

Browse files
committed
Convert internal utilities to pybind11
1 parent 24518d6 commit f33f6cf

File tree

2 files changed

+88
-89
lines changed

2 files changed

+88
-89
lines changed

src/_c_internal_utils.cpp

Lines changed: 87 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,29 @@
1+
#include <stdexcept>
2+
13
#ifdef _WIN32
24
#define WIN32_LEAN_AND_MEAN
35
// Windows 10, for latest HiDPI API support.
46
#define WINVER 0x0A00
57
#define _WIN32_WINNT 0x0A00
68
#endif
7-
#define PY_SSIZE_T_CLEAN
8-
#include <Python.h>
9+
#include <pybind11/pybind11.h>
910
#ifdef __linux__
1011
#include <dlfcn.h>
1112
#endif
1213
#ifdef _WIN32
1314
#include <Objbase.h>
1415
#include <Shobjidl.h>
1516
#include <Windows.h>
17+
#define UNUSED_ON_NON_WINDOWS(x) x
18+
#else
19+
#define UNUSED_ON_NON_WINDOWS Py_UNUSED
1620
#endif
1721

18-
static PyObject*
19-
mpl_display_is_valid(PyObject* module)
22+
namespace py = pybind11;
23+
using namespace pybind11::literals;
24+
25+
static bool
26+
mpl_display_is_valid(void)
2027
{
2128
#ifdef __linux__
2229
void* libX11;
@@ -34,11 +41,10 @@ mpl_display_is_valid(PyObject* module)
3441
XCloseDisplay(display);
3542
}
3643
if (dlclose(libX11)) {
37-
PyErr_SetString(PyExc_RuntimeError, dlerror());
38-
return NULL;
44+
throw std::runtime_error(dlerror());
3945
}
4046
if (display) {
41-
Py_RETURN_TRUE;
47+
return true;
4248
}
4349
}
4450
void* libwayland_client;
@@ -56,84 +62,74 @@ mpl_display_is_valid(PyObject* module)
5662
wl_display_disconnect(display);
5763
}
5864
if (dlclose(libwayland_client)) {
59-
PyErr_SetString(PyExc_RuntimeError, dlerror());
60-
return NULL;
65+
throw std::runtime_error(dlerror());
6166
}
6267
if (display) {
63-
Py_RETURN_TRUE;
68+
return true;
6469
}
6570
}
66-
Py_RETURN_FALSE;
71+
return false;
6772
#else
68-
Py_RETURN_TRUE;
73+
return true;
6974
#endif
7075
}
7176

72-
static PyObject*
73-
mpl_GetCurrentProcessExplicitAppUserModelID(PyObject* module)
77+
static py::object
78+
mpl_GetCurrentProcessExplicitAppUserModelID(void)
7479
{
7580
#ifdef _WIN32
7681
wchar_t* appid = NULL;
7782
HRESULT hr = GetCurrentProcessExplicitAppUserModelID(&appid);
7883
if (FAILED(hr)) {
79-
return PyErr_SetFromWindowsErr(hr);
84+
PyErr_SetFromWindowsErr(hr);
85+
throw py::error_already_set();
8086
}
81-
PyObject* py_appid = PyUnicode_FromWideChar(appid, -1);
87+
auto py_appid = py::cast(appid);
8288
CoTaskMemFree(appid);
8389
return py_appid;
8490
#else
85-
Py_RETURN_NONE;
91+
return py::none();
8692
#endif
8793
}
8894

89-
static PyObject*
90-
mpl_SetCurrentProcessExplicitAppUserModelID(PyObject* module, PyObject* arg)
95+
static void
96+
mpl_SetCurrentProcessExplicitAppUserModelID(const wchar_t* UNUSED_ON_NON_WINDOWS(appid))
9197
{
9298
#ifdef _WIN32
93-
wchar_t* appid = PyUnicode_AsWideCharString(arg, NULL);
94-
if (!appid) {
95-
return NULL;
96-
}
9799
HRESULT hr = SetCurrentProcessExplicitAppUserModelID(appid);
98-
PyMem_Free(appid);
99100
if (FAILED(hr)) {
100-
return PyErr_SetFromWindowsErr(hr);
101+
PyErr_SetFromWindowsErr(hr);
102+
throw py::error_already_set();
101103
}
102-
Py_RETURN_NONE;
103-
#else
104-
Py_RETURN_NONE;
105104
#endif
106105
}
107106

108-
static PyObject*
109-
mpl_GetForegroundWindow(PyObject* module)
107+
static py::object
108+
mpl_GetForegroundWindow(void)
110109
{
111110
#ifdef _WIN32
112-
return PyLong_FromVoidPtr(GetForegroundWindow());
111+
return py::capsule(GetForegroundWindow(), "HWND");
113112
#else
114-
Py_RETURN_NONE;
113+
return py::none();
115114
#endif
116115
}
117116

118-
static PyObject*
119-
mpl_SetForegroundWindow(PyObject* module, PyObject *arg)
117+
static void
118+
mpl_SetForegroundWindow(py::capsule UNUSED_ON_NON_WINDOWS(handle_p))
120119
{
121120
#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;
121+
if (handle_p.name() != "HWND") {
122+
throw std::runtime_error("Handle must be a value returned from Win32_GetForegroundWindow");
123+
}
124+
HWND handle = static_cast<HWND>(handle_p.get_pointer());
125+
if (!SetForegroundWindow(handle)) {
126+
throw std::runtime_error("Error setting window");
127+
}
132128
#endif
133129
}
134130

135-
static PyObject*
136-
mpl_SetProcessDpiAwareness_max(PyObject* module)
131+
static void
132+
mpl_SetProcessDpiAwareness_max(void)
137133
{
138134
#ifdef _WIN32
139135
#ifdef _DPI_AWARENESS_CONTEXTS_
@@ -171,49 +167,52 @@ mpl_SetProcessDpiAwareness_max(PyObject* module)
171167
SetProcessDPIAware();
172168
#endif
173169
#endif
174-
Py_RETURN_NONE;
175170
}
176171

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)
172+
PYBIND11_MODULE(_c_internal_utils, m)
217173
{
218-
return PyModule_Create(&util_module);
174+
m.def(
175+
"display_is_valid", &mpl_display_is_valid,
176+
R"""( --
177+
Check whether the current X11 or Wayland display is valid.
178+
179+
On Linux, returns True if either $DISPLAY is set and XOpenDisplay(NULL)
180+
succeeds, or $WAYLAND_DISPLAY is set and wl_display_connect(NULL)
181+
succeeds.
182+
183+
On other platforms, always returns True.)""");
184+
m.def(
185+
"Win32_GetCurrentProcessExplicitAppUserModelID",
186+
&mpl_GetCurrentProcessExplicitAppUserModelID,
187+
R"""( --
188+
Wrapper for Windows's GetCurrentProcessExplicitAppUserModelID.
189+
190+
On non-Windows platforms, always returns None.)""");
191+
m.def(
192+
"Win32_SetCurrentProcessExplicitAppUserModelID",
193+
&mpl_SetCurrentProcessExplicitAppUserModelID,
194+
"appid"_a, py::pos_only(),
195+
R"""( --
196+
Wrapper for Windows's SetCurrentProcessExplicitAppUserModelID.
197+
198+
On non-Windows platforms, does nothing.)""");
199+
m.def(
200+
"Win32_GetForegroundWindow", &mpl_GetForegroundWindow,
201+
R"""( --
202+
Wrapper for Windows' GetForegroundWindow.
203+
204+
On non-Windows platforms, always returns None.)""");
205+
m.def(
206+
"Win32_SetForegroundWindow", &mpl_SetForegroundWindow,
207+
"hwnd"_a,
208+
R"""( --
209+
Wrapper for Windows' SetForegroundWindow.
210+
211+
On non-Windows platforms, does nothing.)""");
212+
m.def(
213+
"Win32_SetProcessDpiAwareness_max", &mpl_SetProcessDpiAwareness_max,
214+
R"""( --
215+
Set Windows' process DPI awareness to best option available.
216+
217+
On non-Windows platforms, does nothing.)""");
219218
}

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)