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

Skip to content

Commit a567006

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

File tree

2 files changed

+87
-89
lines changed

2 files changed

+87
-89
lines changed

src/_c_internal_utils.cpp

Lines changed: 86 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,28 @@
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+
24+
static bool
25+
mpl_display_is_valid(void)
2026
{
2127
#ifdef __linux__
2228
void* libX11;
@@ -34,11 +40,10 @@ mpl_display_is_valid(PyObject* module)
3440
XCloseDisplay(display);
3541
}
3642
if (dlclose(libX11)) {
37-
PyErr_SetString(PyExc_RuntimeError, dlerror());
38-
return NULL;
43+
throw std::runtime_error(dlerror());
3944
}
4045
if (display) {
41-
Py_RETURN_TRUE;
46+
return true;
4247
}
4348
}
4449
void* libwayland_client;
@@ -56,84 +61,74 @@ mpl_display_is_valid(PyObject* module)
5661
wl_display_disconnect(display);
5762
}
5863
if (dlclose(libwayland_client)) {
59-
PyErr_SetString(PyExc_RuntimeError, dlerror());
60-
return NULL;
64+
throw std::runtime_error(dlerror());
6165
}
6266
if (display) {
63-
Py_RETURN_TRUE;
67+
return true;
6468
}
6569
}
66-
Py_RETURN_FALSE;
70+
return false;
6771
#else
68-
Py_RETURN_TRUE;
72+
return true;
6973
#endif
7074
}
7175

72-
static PyObject*
73-
mpl_GetCurrentProcessExplicitAppUserModelID(PyObject* module)
76+
static py::object
77+
mpl_GetCurrentProcessExplicitAppUserModelID(void)
7478
{
7579
#ifdef _WIN32
7680
wchar_t* appid = NULL;
7781
HRESULT hr = GetCurrentProcessExplicitAppUserModelID(&appid);
7882
if (FAILED(hr)) {
79-
return PyErr_SetFromWindowsErr(hr);
83+
PyErr_SetFromWindowsErr(hr);
84+
throw py::error_already_set();
8085
}
81-
PyObject* py_appid = PyUnicode_FromWideChar(appid, -1);
86+
auto py_appid = py::cast(appid);
8287
CoTaskMemFree(appid);
8388
return py_appid;
8489
#else
85-
Py_RETURN_NONE;
90+
return py::none();
8691
#endif
8792
}
8893

89-
static PyObject*
90-
mpl_SetCurrentProcessExplicitAppUserModelID(PyObject* module, PyObject* arg)
94+
static void
95+
mpl_SetCurrentProcessExplicitAppUserModelID(const wchar_t* UNUSED_ON_NON_WINDOWS(appid))
9196
{
9297
#ifdef _WIN32
93-
wchar_t* appid = PyUnicode_AsWideCharString(arg, NULL);
94-
if (!appid) {
95-
return NULL;
96-
}
9798
HRESULT hr = SetCurrentProcessExplicitAppUserModelID(appid);
98-
PyMem_Free(appid);
9999
if (FAILED(hr)) {
100-
return PyErr_SetFromWindowsErr(hr);
100+
PyErr_SetFromWindowsErr(hr);
101+
throw py::error_already_set();
101102
}
102-
Py_RETURN_NONE;
103-
#else
104-
Py_RETURN_NONE;
105103
#endif
106104
}
107105

108-
static PyObject*
109-
mpl_GetForegroundWindow(PyObject* module)
106+
static py::object
107+
mpl_GetForegroundWindow(void)
110108
{
111109
#ifdef _WIN32
112-
return PyLong_FromVoidPtr(GetForegroundWindow());
110+
return py::capsule(GetForegroundWindow(), "HWND");
113111
#else
114-
Py_RETURN_NONE;
112+
return py::none();
115113
#endif
116114
}
117115

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

135-
static PyObject*
136-
mpl_SetProcessDpiAwareness_max(PyObject* module)
130+
static void
131+
mpl_SetProcessDpiAwareness_max(void)
137132
{
138133
#ifdef _WIN32
139134
#ifdef _DPI_AWARENESS_CONTEXTS_
@@ -171,49 +166,52 @@ mpl_SetProcessDpiAwareness_max(PyObject* module)
171166
SetProcessDPIAware();
172167
#endif
173168
#endif
174-
Py_RETURN_NONE;
175169
}
176170

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

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)