@@ -16,25 +16,143 @@ namespace py = pybind11;
1616namespace em = emscripten;
1717
1818namespace pyjs
19- {
20- void export_pyjs_module (py::module_& pyjs_module)
19+ {
20+
21+ struct LoopContext
2122 {
22- export_js_proxy (pyjs_module);
23- try
24- {
25- // pyjs_core_pseudo_init(pyjs_module);
26- // pyjs_extend_js_val_pseudo_init(pyjs_module);
27- // pyjs_error_handling_pseudo_init(pyjs_module);
28- // pyjs_convert_pseudo_init(pyjs_module);
29- // pyjs_convert_py_to_js_pseudo_init(pyjs_module);
30- // pyjs_webloop_pseudo_init(pyjs_module);
31- // pyjs_pyodide_polyfill_pseudo_init(pyjs_module);
23+ py::object m_callback;
24+ bool m_cancel_loop_on_error = true ; // default to true
25+ bool m_exit_loop = false ;
26+
27+ LoopContext (py::object callback, bool cancel_loop_on_error)
28+ : m_callback(std::move(callback)), m_cancel_loop_on_error(cancel_loop_on_error), m_exit_loop(false ) {}
29+ };
30+
31+
32+
33+
34+ // void wrapped_callback_without_cancel(void* cb_ptr) {
35+ // // Reinterpret the void pointer back to a PyObject pointer
36+ // auto py_object = reinterpret_cast<PyObject*>(cb_ptr);
37+ // // We can use PyObject_CallObject to call the Python function
38+ // if (PyObject_CallNoArgs(py_object) == nullptr) {
39+ // // If the call fails, we can print the error
40+ // std::cerr << "Error calling Python callback." << std::endl;
41+ // PyErr_Print();
42+
43+ // }
44+ // };
45+ void wrapped_callback (void * cb_ptr) {
46+ // Reinterpret the void pointer back to a PyObject pointer
47+ auto py_object = reinterpret_cast <PyObject*>(cb_ptr);
48+ if (!py_object) {
49+ std::cerr << " Error: callback pointer is null." << std::endl;
3250 }
33- catch (py::error_already_set& e)
34- {
35- std::cout << " error: " << e.what () << " \n " ;
36- throw e;
51+ // We can use PyObject_CallObject to call the Python function
52+ if (PyObject_CallNoArgs (py_object) == nullptr ) {
53+ // If the call fails, we can print the error
54+ std::cerr << " Error calling Python callback:" << std::endl;
55+ PyErr_Print ();
3756 }
57+ };
58+
59+ void noop_callback () {
60+ // This is a no-op callback, it does nothing
61+
62+ // we see a strange error when we run emscripten_cancel_main_loop
63+ // **WITHOUT setting a new loop right away**
64+ // so instead of just cancelling the loop, we need
65+ // to cancel and right away set a new loop
66+ }
67+
68+ void self_cancel_callback () {
69+ emscripten_cancel_main_loop ();
70+ };
71+
72+
73+ void export_main_loop_callbacks (py::module_& pyjs_module)
74+ {
75+
76+
77+
78+ // class for loop context
79+ py::class_<LoopContext>(pyjs_module, " LoopContext" )
80+ .def (py::init<py::object, bool >(), py::arg (" callback" ), py::arg (" cancel_loop_on_error" ) = true )
81+ .def_readwrite (" exit_loop" , &LoopContext::m_exit_loop)
82+ ;
83+
84+
85+
86+
87+
88+ // Export main loop callbacks
89+ pyjs_module.def (" _set_main_loop_callback" , [](py::handle callback, int fps) {
90+
91+ // get a PyObject * from the handle
92+ auto py_object = callback.ptr ();
93+
94+ // convert the PyObject to void*
95+ void * callback_ptr = reinterpret_cast <void *>(py_object);
96+
97+
98+ // use emscripten_set_main_loop_arg
99+ emscripten_set_main_loop_arg (
100+ wrapped_callback,
101+ callback_ptr, // pass the callback pointer as argument
102+ fps, // frames per second
103+ false
104+ );
105+ });
106+
107+ // explicit cancel main loop
108+ pyjs_module.def (" _cancel_main_loop" , []() {
109+ // This will cancel the main loop if it is currently running
110+ emscripten_cancel_main_loop ();
111+ });
112+
113+ pyjs_module.def (" _set_noop_main_loop" , []() {
114+ // This will set a no-op main loop
115+ emscripten_set_main_loop (noop_callback, 1 , false ); // set a no-op loop to avoid errors
116+ });
117+
118+
119+ // pyjs_module.def("set_main_loop_callback_hl", [](py::handle & callback, int fps) {
120+
121+ // // get a PyObject * from the handle
122+ // void * handle_ptr = reinterpret_cast<void*>(&callback);
123+
124+
125+
126+ // // create a lambda without any caputres taking the callback pointer
127+ // auto wrapped_callback = [](void* cb_ptr) {
128+
129+
130+ // py::handle* handle = reinterpret_cast<py::handle*>(cb_ptr);
131+
132+
133+ // // We can use PyObject_CallObject to call the Python function
134+
135+ // };
136+
137+ // // use emscripten_set_main_loop_arg
138+ // emscripten_set_main_loop_arg(
139+ // wrapped_callback,
140+ // callback_ptr, // pass the callback pointer as argument
141+ // fps, // frames per second
142+ // false
143+ // );
144+ // });
145+
146+
147+
148+ }
149+
150+
151+
152+ void export_pyjs_module (py::module_& pyjs_module)
153+ {
154+ export_js_proxy (pyjs_module);
155+ export_main_loop_callbacks (pyjs_module);
38156
39157 }
40158}
0 commit comments