1 /******************************************************************************
2 Copyright (C) 2017 by Hugh Bailey <jim@obsproject.com>
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16 ******************************************************************************/
17
18 #include <obs-module.h>
19 #include <obs-frontend-api.h>
20
21 #include "obs-scripting-python.h"
22
23 #define libobs_to_py(type, obs_obj, ownership, py_obj) \
24 libobs_to_py_(#type " *", obs_obj, ownership, py_obj, NULL, __func__, \
25 __LINE__)
26 #define py_to_libobs(type, py_obj, libobs_out) \
27 py_to_libobs_(#type " *", py_obj, libobs_out, NULL, __func__, __LINE__)
28
29 /* ----------------------------------- */
30
get_scene_names(PyObject * self,PyObject * args)31 static PyObject *get_scene_names(PyObject *self, PyObject *args)
32 {
33 char **names = obs_frontend_get_scene_names();
34 char **name = names;
35
36 PyObject *list = PyList_New(0);
37
38 while (name && *name) {
39 PyObject *py_name = PyUnicode_FromString(*name);
40 if (py_name) {
41 PyList_Append(list, py_name);
42 Py_DECREF(py_name);
43 }
44 name++;
45 }
46
47 UNUSED_PARAMETER(self);
48 UNUSED_PARAMETER(args);
49
50 bfree(names);
51 return list;
52 }
53
get_scenes(PyObject * self,PyObject * args)54 static PyObject *get_scenes(PyObject *self, PyObject *args)
55 {
56 struct obs_frontend_source_list list = {0};
57 obs_frontend_get_scenes(&list);
58
59 PyObject *ret = PyList_New(0);
60
61 for (size_t i = 0; i < list.sources.num; i++) {
62 obs_source_t *source = list.sources.array[i];
63 PyObject *py_source;
64
65 if (libobs_to_py(obs_source_t, source, false, &py_source)) {
66 PyList_Append(ret, py_source);
67 Py_DECREF(py_source);
68 }
69 }
70
71 UNUSED_PARAMETER(self);
72 UNUSED_PARAMETER(args);
73
74 da_free(list.sources);
75 return ret;
76 }
77
get_current_scene(PyObject * self,PyObject * args)78 static PyObject *get_current_scene(PyObject *self, PyObject *args)
79 {
80 obs_source_t *source = obs_frontend_get_current_scene();
81
82 PyObject *py_source;
83 if (!libobs_to_py(obs_source_t, source, false, &py_source)) {
84 obs_source_release(source);
85 return python_none();
86 }
87
88 UNUSED_PARAMETER(self);
89 UNUSED_PARAMETER(args);
90 return py_source;
91 }
92
set_current_scene(PyObject * self,PyObject * args)93 static PyObject *set_current_scene(PyObject *self, PyObject *args)
94 {
95 PyObject *py_source;
96 obs_source_t *source = NULL;
97
98 if (!parse_args(args, "O", &py_source))
99 return python_none();
100 if (!py_to_libobs(obs_source_t, py_source, &source))
101 return python_none();
102
103 UNUSED_PARAMETER(self);
104
105 obs_frontend_set_current_scene(source);
106 return python_none();
107 }
108
get_transitions(PyObject * self,PyObject * args)109 static PyObject *get_transitions(PyObject *self, PyObject *args)
110 {
111 struct obs_frontend_source_list list = {0};
112 obs_frontend_get_transitions(&list);
113
114 PyObject *ret = PyList_New(0);
115
116 for (size_t i = 0; i < list.sources.num; i++) {
117 obs_source_t *source = list.sources.array[i];
118 PyObject *py_source;
119
120 if (libobs_to_py(obs_source_t, source, false, &py_source)) {
121 PyList_Append(ret, py_source);
122 Py_DECREF(py_source);
123 }
124 }
125
126 UNUSED_PARAMETER(self);
127 UNUSED_PARAMETER(args);
128
129 da_free(list.sources);
130 return ret;
131 }
132
get_current_transition(PyObject * self,PyObject * args)133 static PyObject *get_current_transition(PyObject *self, PyObject *args)
134 {
135 obs_source_t *source = obs_frontend_get_current_transition();
136
137 PyObject *py_source;
138 if (!libobs_to_py(obs_source_t, source, false, &py_source)) {
139 obs_source_release(source);
140 return python_none();
141 }
142
143 UNUSED_PARAMETER(self);
144 UNUSED_PARAMETER(args);
145 return py_source;
146 }
147
set_current_transition(PyObject * self,PyObject * args)148 static PyObject *set_current_transition(PyObject *self, PyObject *args)
149 {
150 PyObject *py_source;
151 obs_source_t *source = NULL;
152
153 if (!parse_args(args, "O", &py_source))
154 return python_none();
155 if (!py_to_libobs(obs_source_t, py_source, &source))
156 return python_none();
157
158 UNUSED_PARAMETER(self);
159
160 obs_frontend_set_current_transition(source);
161 return python_none();
162 }
163
get_scene_collections(PyObject * self,PyObject * args)164 static PyObject *get_scene_collections(PyObject *self, PyObject *args)
165 {
166 char **names = obs_frontend_get_scene_collections();
167 char **name = names;
168
169 PyObject *list = PyList_New(0);
170
171 while (name && *name) {
172 PyObject *py_name = PyUnicode_FromString(*name);
173 if (py_name) {
174 PyList_Append(list, py_name);
175 Py_DECREF(py_name);
176 }
177 name++;
178 }
179
180 UNUSED_PARAMETER(self);
181 UNUSED_PARAMETER(args);
182
183 bfree(names);
184 return list;
185 }
186
get_current_scene_collection(PyObject * self,PyObject * args)187 static PyObject *get_current_scene_collection(PyObject *self, PyObject *args)
188 {
189 char *name = obs_frontend_get_current_scene_collection();
190 PyObject *ret = PyUnicode_FromString(name);
191 bfree(name);
192
193 UNUSED_PARAMETER(self);
194 UNUSED_PARAMETER(args);
195 return ret;
196 }
197
set_current_scene_collection(PyObject * self,PyObject * args)198 static PyObject *set_current_scene_collection(PyObject *self, PyObject *args)
199 {
200 const char *name;
201 if (!parse_args(args, "s", &name))
202 return python_none();
203
204 UNUSED_PARAMETER(self);
205
206 obs_frontend_set_current_scene_collection(name);
207 return python_none();
208 }
209
get_profiles(PyObject * self,PyObject * args)210 static PyObject *get_profiles(PyObject *self, PyObject *args)
211 {
212 char **names = obs_frontend_get_profiles();
213 char **name = names;
214
215 PyObject *list = PyList_New(0);
216
217 while (name && *name) {
218 PyObject *py_name = PyUnicode_FromString(*name);
219 if (py_name) {
220 PyList_Append(list, py_name);
221 Py_DECREF(py_name);
222 }
223 name++;
224 }
225
226 UNUSED_PARAMETER(self);
227 UNUSED_PARAMETER(args);
228
229 bfree(names);
230 return list;
231 }
232
get_current_profile(PyObject * self,PyObject * args)233 static PyObject *get_current_profile(PyObject *self, PyObject *args)
234 {
235 char *name = obs_frontend_get_current_profile();
236 PyObject *ret = PyUnicode_FromString(name);
237 bfree(name);
238
239 UNUSED_PARAMETER(self);
240 UNUSED_PARAMETER(args);
241 return ret;
242 }
243
set_current_profile(PyObject * self,PyObject * args)244 static PyObject *set_current_profile(PyObject *self, PyObject *args)
245 {
246 const char *name;
247 if (!parse_args(args, "s", &name))
248 return python_none();
249
250 UNUSED_PARAMETER(self);
251
252 obs_frontend_set_current_profile(name);
253 return python_none();
254 }
255
256 /* ----------------------------------- */
257
frontend_save_callback(obs_data_t * save_data,bool saving,void * priv)258 static void frontend_save_callback(obs_data_t *save_data, bool saving,
259 void *priv)
260 {
261 struct python_obs_callback *cb = priv;
262
263 if (cb->base.removed) {
264 obs_frontend_remove_save_callback(frontend_save_callback, cb);
265 return;
266 }
267
268 lock_python();
269
270 PyObject *py_save_data;
271
272 if (libobs_to_py(obs_data_t, save_data, false, &py_save_data)) {
273 PyObject *args = Py_BuildValue("(Op)", py_save_data, saving);
274
275 struct python_obs_callback *last_cb = cur_python_cb;
276 cur_python_cb = cb;
277 cur_python_script = (struct obs_python_script *)cb->base.script;
278
279 PyObject *py_ret = PyObject_CallObject(cb->func, args);
280 Py_XDECREF(py_ret);
281 py_error();
282
283 cur_python_script = NULL;
284 cur_python_cb = last_cb;
285
286 Py_XDECREF(args);
287 Py_XDECREF(py_save_data);
288 }
289
290 unlock_python();
291 }
292
remove_save_callback(PyObject * self,PyObject * args)293 static PyObject *remove_save_callback(PyObject *self, PyObject *args)
294 {
295 struct obs_python_script *script = cur_python_script;
296 PyObject *py_cb = NULL;
297
298 UNUSED_PARAMETER(self);
299
300 if (!parse_args(args, "O", &py_cb))
301 return python_none();
302 if (!py_cb || !PyFunction_Check(py_cb))
303 return python_none();
304
305 struct python_obs_callback *cb =
306 find_python_obs_callback(script, py_cb);
307 if (cb)
308 remove_python_obs_callback(cb);
309 return python_none();
310 }
311
add_save_callback_defer(void * cb)312 static void add_save_callback_defer(void *cb)
313 {
314 obs_frontend_add_save_callback(frontend_save_callback, cb);
315 }
316
add_save_callback(PyObject * self,PyObject * args)317 static PyObject *add_save_callback(PyObject *self, PyObject *args)
318 {
319 struct obs_python_script *script = cur_python_script;
320 PyObject *py_cb = NULL;
321
322 UNUSED_PARAMETER(self);
323
324 if (!parse_args(args, "O", &py_cb))
325 return python_none();
326 if (!py_cb || !PyFunction_Check(py_cb))
327 return python_none();
328
329 struct python_obs_callback *cb = add_python_obs_callback(script, py_cb);
330 defer_call_post(add_save_callback_defer, cb);
331 return python_none();
332 }
333
frontend_event_callback(enum obs_frontend_event event,void * priv)334 static void frontend_event_callback(enum obs_frontend_event event, void *priv)
335 {
336 struct python_obs_callback *cb = priv;
337
338 if (cb->base.removed) {
339 obs_frontend_remove_event_callback(frontend_event_callback, cb);
340 return;
341 }
342
343 lock_python();
344
345 PyObject *args = Py_BuildValue("(i)", event);
346
347 struct python_obs_callback *last_cb = cur_python_cb;
348 cur_python_cb = cb;
349 cur_python_script = (struct obs_python_script *)cb->base.script;
350
351 PyObject *py_ret = PyObject_CallObject(cb->func, args);
352 Py_XDECREF(py_ret);
353 py_error();
354
355 cur_python_script = NULL;
356 cur_python_cb = last_cb;
357
358 Py_XDECREF(args);
359
360 unlock_python();
361 }
362
remove_event_callback(PyObject * self,PyObject * args)363 static PyObject *remove_event_callback(PyObject *self, PyObject *args)
364 {
365 struct obs_python_script *script = cur_python_script;
366 PyObject *py_cb = NULL;
367
368 UNUSED_PARAMETER(self);
369
370 if (!parse_args(args, "O", &py_cb))
371 return python_none();
372 if (!py_cb || !PyFunction_Check(py_cb))
373 return python_none();
374
375 struct python_obs_callback *cb =
376 find_python_obs_callback(script, py_cb);
377 if (cb)
378 remove_python_obs_callback(cb);
379 return python_none();
380 }
381
add_event_callback_defer(void * cb)382 static void add_event_callback_defer(void *cb)
383 {
384 obs_frontend_add_event_callback(frontend_event_callback, cb);
385 }
386
add_event_callback(PyObject * self,PyObject * args)387 static PyObject *add_event_callback(PyObject *self, PyObject *args)
388 {
389 struct obs_python_script *script = cur_python_script;
390 PyObject *py_cb = NULL;
391
392 UNUSED_PARAMETER(self);
393
394 if (!parse_args(args, "O", &py_cb))
395 return python_none();
396 if (!py_cb || !PyFunction_Check(py_cb))
397 return python_none();
398
399 struct python_obs_callback *cb = add_python_obs_callback(script, py_cb);
400 defer_call_post(add_event_callback_defer, cb);
401 return python_none();
402 }
403
404 /* ----------------------------------- */
405
add_python_frontend_funcs(PyObject * module)406 void add_python_frontend_funcs(PyObject *module)
407 {
408 static PyMethodDef funcs[] = {
409 #define DEF_FUNC(c) {"obs_frontend_" #c, c, METH_VARARGS, NULL}
410
411 DEF_FUNC(get_scene_names),
412 DEF_FUNC(get_scenes),
413 DEF_FUNC(get_current_scene),
414 DEF_FUNC(set_current_scene),
415 DEF_FUNC(get_transitions),
416 DEF_FUNC(get_current_transition),
417 DEF_FUNC(set_current_transition),
418 DEF_FUNC(get_scene_collections),
419 DEF_FUNC(get_current_scene_collection),
420 DEF_FUNC(set_current_scene_collection),
421 DEF_FUNC(get_profiles),
422 DEF_FUNC(get_current_profile),
423 DEF_FUNC(set_current_profile),
424 DEF_FUNC(remove_save_callback),
425 DEF_FUNC(add_save_callback),
426 DEF_FUNC(remove_event_callback),
427 DEF_FUNC(add_event_callback),
428
429 #undef DEF_FUNC
430 {0}};
431
432 add_functions_to_py_module(module, funcs);
433 }
434