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}
0 commit comments