Blender V4.3
bpy_rna_context.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
11#include <Python.h>
12
13#include "BLI_listbase.h"
14#include "BLI_utildefines.h"
15
16#include "BKE_context.hh"
17#include "BKE_main.hh"
18#include "BKE_screen.hh"
19#include "BKE_workspace.hh"
20
21#include "WM_api.hh"
22#include "WM_types.hh"
23
24#include "bpy_rna_context.hh"
25
27
28#include "RNA_access.hh"
29#include "RNA_prototypes.hh"
30
31#include "bpy_rna.hh"
32
33/* -------------------------------------------------------------------- */
38{
39 if (screen == nullptr) {
40 return;
41 }
42 if (screen == WM_window_get_active_screen(win)) {
43 return;
44 }
45
46 WorkSpace *workspace;
47 BKE_workspace_layout_find_global(CTX_data_main(C), screen, &workspace);
48 /* Changing workspace instead of just screen as they are tied. */
49 WM_window_set_active_workspace(C, win, workspace);
50 WM_window_set_active_screen(win, workspace, screen);
51}
52
56static bool wm_check_screen_switch_supported(const bScreen *screen)
57{
58 if (screen->temp != 0) {
59 return false;
60 }
62 return false;
63 }
64 return true;
65}
66
67static bool wm_check_window_exists(const Main *bmain, const wmWindow *win)
68{
69 LISTBASE_FOREACH (wmWindowManager *, wm, &bmain->wm) {
70 if (BLI_findindex(&wm->windows, win) != -1) {
71 return true;
72 }
73 }
74 return false;
75}
76
77static bool wm_check_screen_exists(const Main *bmain, const bScreen *screen)
78{
79 if (BLI_findindex(&bmain->screens, screen) != -1) {
80 return true;
81 }
82 return false;
83}
84
85static bool wm_check_area_exists(const wmWindow *win, const bScreen *screen, const ScrArea *area)
86{
87 if (win && (BLI_findindex(&win->global_areas.areabase, area) != -1)) {
88 return true;
89 }
90 if (screen && (BLI_findindex(&screen->areabase, area) != -1)) {
91 return true;
92 }
93 return false;
94}
95
96static bool wm_check_region_exists(const bScreen *screen,
97 const ScrArea *area,
98 const ARegion *region)
99{
100 if (screen && (BLI_findindex(&screen->regionbase, region) != -1)) {
101 return true;
102 }
103 if (area && (BLI_findindex(&area->regionbase, region) != -1)) {
104 return true;
105 }
106 return false;
107}
108
111/* -------------------------------------------------------------------- */
125
127 PyObject_HEAD /* Required Python macro. */
129
132
133 struct {
140
152};
153
158
160{
161 bContext *C = self->context;
162 Main *bmain = CTX_data_main(C);
163
164 CTX_py_state_push(C, &self->py_state, self->py_state_context_dict);
165
166 self->ctx_init.win = CTX_wm_window(C);
167 self->ctx_init.screen = self->ctx_init.win ? WM_window_get_active_screen(self->ctx_init.win) :
168 CTX_wm_screen(C);
169 self->ctx_init.area = CTX_wm_area(C);
170 self->ctx_init.region = CTX_wm_region(C);
171
172 wmWindow *win = self->ctx_temp.win_is_set ? self->ctx_temp.win : self->ctx_init.win;
173 bScreen *screen = self->ctx_temp.screen_is_set ? self->ctx_temp.screen : self->ctx_init.screen;
174 ScrArea *area = self->ctx_temp.area_is_set ? self->ctx_temp.area : self->ctx_init.area;
175 ARegion *region = self->ctx_temp.region_is_set ? self->ctx_temp.region : self->ctx_init.region;
176
177 self->ctx_init.win_is_set = (self->ctx_init.win != win);
178 self->ctx_init.screen_is_set = (self->ctx_init.screen != screen);
179 self->ctx_init.area_is_set = (self->ctx_init.area != area);
180 self->ctx_init.region_is_set = (self->ctx_init.region != region);
181
182 /* When the screen isn't passed but a window is, match the screen to the window,
183 * it's important to do this after setting `self->ctx_init.screen_is_set` because the screen is
184 * *not* set, only the window, restoring the window will also restore its screen, see #116297. */
185 if ((self->ctx_temp.win_is_set == true) && (self->ctx_temp.screen_is_set == false)) {
186 screen = win ? WM_window_get_active_screen(win) : nullptr;
187 }
188
189 /* NOTE(@ideasman42): Regarding sanity checks.
190 * There are 3 different situations to be accounted for here regarding overriding windowing data.
191 *
192 * - 1) Nothing is overridden.
193 * Simple, no sanity checks needed.
194 *
195 * - 2) Some members are overridden.
196 * Check the state is consistent (that the region is part the area or screen for e.g.).
197 *
198 * - 3) Some members are overridden *but* the context members are unchanged.
199 * This is a less obvious case which often happens when a Python script copies the context
200 * typically via `context.copy()`, manipulates it and passes it in as keyword arguments.
201 *
202 * A naive approach could be to behave as if these arguments weren't passed in
203 * which would work in many situations however there is a difference
204 * since these members are used to restore the context afterwards.
205 * It's possible a script might use this context-manager to *pin* the context,
206 * running actions that change the context, relying on the context to be restored.
207 *
208 * When error-checking unchanged context members some error checks must be skipped
209 * such as the check to disallow temporary screens since that could break using
210 * `temp_override(..)` running with the current context from a render-window for e.g.
211 *
212 * In fact all sanity checks could be disabled when the members involved remain unchanged
213 * however it's possible Python scripts corrupt Blender's internal windowing state so keeping
214 * the checks is harmless and alerts developers early on that something is wrong.
215 */
216
217 if (self->ctx_temp.region_is_set && (region != nullptr)) {
218 if (screen == nullptr && area == nullptr) {
219 PyErr_SetString(PyExc_TypeError, "Region set with screen & area set to None");
220 return nullptr;
221 }
222 if (!wm_check_region_exists(screen, area, region)) {
223 PyErr_SetString(PyExc_TypeError, "Region not found in area or screen");
224 return nullptr;
225 }
226 }
227
228 if (self->ctx_temp.area_is_set && (area != nullptr)) {
229 if (win == nullptr && screen == nullptr) {
230 PyErr_SetString(PyExc_TypeError, "Area set with window & screen set to None");
231 return nullptr;
232 }
233 if (!wm_check_area_exists(win, screen, area)) {
234 PyErr_SetString(PyExc_TypeError, "Area not found in screen");
235 return nullptr;
236 }
237 }
238
239 if (self->ctx_temp.screen_is_set && (screen != nullptr)) {
240 if (win == nullptr) {
241 PyErr_SetString(PyExc_TypeError, "Screen set with null window");
242 return nullptr;
243 }
244 if (!wm_check_screen_exists(bmain, screen)) {
245 PyErr_SetString(PyExc_TypeError, "Screen not found");
246 return nullptr;
247 }
248
249 /* Skip some checks when the screen is unchanged. */
250 if (self->ctx_init.screen_is_set) {
251 /* Switching away from a temporary screen isn't supported. */
252 if ((self->ctx_init.screen != nullptr) &&
253 !wm_check_screen_switch_supported(self->ctx_init.screen))
254 {
255 PyErr_SetString(PyExc_TypeError,
256 "Overriding context with an active temporary screen isn't supported");
257 return nullptr;
258 }
260 PyErr_SetString(PyExc_TypeError,
261 "Overriding context with temporary screen isn't supported");
262 return nullptr;
263 }
264 if (BKE_workspace_layout_find_global(bmain, screen, nullptr) == nullptr) {
265 PyErr_SetString(PyExc_TypeError, "Screen has no workspace");
266 return nullptr;
267 }
268
269 LISTBASE_FOREACH (wmWindowManager *, wm, &bmain->wm) {
270 LISTBASE_FOREACH (wmWindow *, win_iter, &wm->windows) {
271 if (win_iter == win) {
272 continue;
273 }
274 if (screen == WM_window_get_active_screen(win_iter)) {
275 PyErr_SetString(PyExc_TypeError, "Screen is used by another window");
276 return nullptr;
277 }
278 }
279 }
280 }
281 }
282
283 if (self->ctx_temp.win_is_set && (win != nullptr)) {
284 if (!wm_check_window_exists(bmain, win)) {
285 PyErr_SetString(PyExc_TypeError, "Window not found");
286 return nullptr;
287 }
288 }
289
290 /* Manipulate the context (setup). */
291 if (self->ctx_temp.screen_is_set) {
292 self->ctx_temp_orig.screen = WM_window_get_active_screen(win);
293 bpy_rna_context_temp_set_screen_for_window(C, win, self->ctx_temp.screen);
294 }
295
296 /* NOTE: always set these members, even when they are equal to the current values because
297 * setting the window (for e.g.) clears the area & region, setting the area clears the region.
298 * While it would be useful in some cases to leave the context as-is when setting members
299 * to their current values.
300 *
301 * Favor predictable behavior, where setting a member *always* clears the nested
302 * values it contains - no matter the state of the current context.
303 * If this difference is important, the caller can always detect this case and avoid
304 * passing in the context override altogether. */
305
306 if (self->ctx_temp.win_is_set) {
307 CTX_wm_window_set(C, self->ctx_temp.win);
308 }
309 if (self->ctx_temp.screen_is_set) {
310 CTX_wm_screen_set(C, self->ctx_temp.screen);
311 }
312 if (self->ctx_temp.area_is_set) {
313 CTX_wm_area_set(C, self->ctx_temp.area);
314 }
315 if (self->ctx_temp.region_is_set) {
316 CTX_wm_region_set(C, self->ctx_temp.region);
317 }
318
319 Py_RETURN_NONE;
320}
321
323 PyObject * /*args*/)
324{
325 bContext *C = self->context;
326
327 Main *bmain = CTX_data_main(C);
328
329 /* Manipulate the context (restore). */
330 if (self->ctx_temp.screen_is_set) {
331 if (self->ctx_temp_orig.screen && wm_check_screen_exists(bmain, self->ctx_temp_orig.screen)) {
332 wmWindow *win = self->ctx_temp.win_is_set ? self->ctx_temp.win : self->ctx_init.win;
333 if (win && wm_check_window_exists(bmain, win)) {
334 /* Disallow switching away from temporary-screens & full-screen areas, while it could be
335 * useful to support this closing a these screens uses different and more involved logic
336 * compared with switching between user managed screens, see: #117188. */
338 bpy_rna_context_temp_set_screen_for_window(C, win, self->ctx_temp_orig.screen);
339 }
340 }
341 }
342 }
343
344 /* Account for the window to be freed on file-read,
345 * in this case the window should not be restored, see: #92818.
346 * Also account for other windowing members to be removed on exit,
347 * in this case the context is cleared. */
348 bool do_restore = true;
349
350 /* Restore context members as needed.
351 *
352 * The checks here behaves as follows:
353 * - When `self->ctx_init.win_is_set` is true, the window was changed by the override.
354 * in this case restore the initial window.
355 * - When `self->ctx_temp.win_is_set` is true, the window was set to the current value.
356 * Setting the window (even to the current value) must be accounted for
357 * because setting the window clears the area and the region members,
358 * which must now be restored.
359 *
360 * `is_container_set` is used to detect if nested context members need to be restored.
361 * The comments above refer to the window, it also applies to the screen containing an area
362 * and area which contains a region. */
363 bool is_container_set = false;
364
365 /* Handle Window. */
366 if (do_restore) {
367 if (self->ctx_init.win && !wm_check_window_exists(bmain, self->ctx_init.win)) {
368 CTX_wm_window_set(C, nullptr);
369 do_restore = false;
370 }
371
372 if (do_restore) {
373 if (self->ctx_init.win_is_set) {
374 CTX_wm_window_set(C, self->ctx_init.win);
375 is_container_set = true;
376 }
377 else if (self->ctx_temp.win_is_set) {
378 if (self->ctx_init.win == CTX_wm_window(C)) {
379 is_container_set = true;
380 }
381 else {
382 /* If the context changed, it's incorrect to attempt to restored nested members,
383 * in this case leave the context as-is, see: #119202. */
384 do_restore = false;
385 }
386 }
387 }
388 }
389
390 /* Handle Screen. */
391 if (do_restore) {
392 if (self->ctx_init.screen && !wm_check_screen_exists(bmain, self->ctx_init.screen)) {
393 CTX_wm_screen_set(C, nullptr);
394 do_restore = false;
395 }
396
397 if (do_restore) {
398 if (self->ctx_init.screen_is_set || is_container_set) {
399 CTX_wm_screen_set(C, self->ctx_init.screen);
400 is_container_set = true;
401 }
402 else if (self->ctx_temp.screen_is_set) {
403 if (self->ctx_init.screen == CTX_wm_screen(C)) {
404 is_container_set = true;
405 }
406 else {
407 do_restore = false;
408 }
409 }
410 }
411 }
412
413 /* Handle Area. */
414 if (do_restore) {
415 if (self->ctx_init.area &&
416 !wm_check_area_exists(self->ctx_init.win, self->ctx_init.screen, self->ctx_init.area))
417 {
418 CTX_wm_area_set(C, nullptr);
419 do_restore = false;
420 }
421
422 if (do_restore) {
423 if (self->ctx_init.area_is_set || is_container_set) {
424 CTX_wm_area_set(C, self->ctx_init.area);
425 is_container_set = true;
426 }
427 else if (self->ctx_temp.area_is_set) {
428 if (self->ctx_init.area == CTX_wm_area(C)) {
429 is_container_set = true;
430 }
431 else {
432 do_restore = false;
433 }
434 }
435 }
436 }
437
438 /* Handle Region. */
439 if (do_restore) {
440 if (self->ctx_init.region &&
441 !wm_check_region_exists(self->ctx_init.screen, self->ctx_init.area, self->ctx_init.region))
442 {
443 CTX_wm_region_set(C, nullptr);
444 do_restore = false;
445 }
446
447 if (do_restore) {
448 if (self->ctx_init.region_is_set || is_container_set) {
449 CTX_wm_region_set(C, self->ctx_init.region);
450 is_container_set = true;
451 }
452 /* Enable is there is ever data nested within the region. */
453 else if (false && self->ctx_temp.region_is_set) {
454 if (self->ctx_init.region == CTX_wm_region(C)) {
455 is_container_set = true;
456 }
457 else {
458 do_restore = false;
459 }
460 }
461 }
462 }
463 UNUSED_VARS(is_container_set, do_restore);
464
465 /* Finished restoring the context. */
466
467 /* A copy may have been made when writing context members, see #BPY_context_dict_clear_members */
468 PyObject *context_dict_test = static_cast<PyObject *>(CTX_py_dict_get(C));
469 if (context_dict_test && (context_dict_test != self->py_state_context_dict)) {
470 Py_DECREF(context_dict_test);
471 }
472 CTX_py_state_pop(C, &self->py_state);
473 Py_CLEAR(self->py_state_context_dict);
474
475 Py_RETURN_NONE;
476}
477
478#if (defined(__GNUC__) && !defined(__clang__))
479# pragma GCC diagnostic push
480# pragma GCC diagnostic ignored "-Wcast-function-type"
481#endif
482
484 {"__enter__", (PyCFunction)bpy_rna_context_temp_override_enter, METH_NOARGS},
485 {"__exit__", (PyCFunction)bpy_rna_context_temp_override_exit, METH_VARARGS},
486 {nullptr},
487};
488
489#if (defined(__GNUC__) && !defined(__clang__))
490# pragma GCC diagnostic pop
491#endif
492
493static PyTypeObject BPyContextTempOverride_Type = {
494 /*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
495 /*tp_name*/ "ContextTempOverride",
496 /*tp_basicsize*/ sizeof(BPyContextTempOverride),
497 /*tp_itemsize*/ 0,
498 /*tp_dealloc*/ (destructor)bpy_rna_context_temp_override__tp_dealloc,
499 /*tp_vectorcall_offset*/ 0,
500 /*tp_getattr*/ nullptr,
501 /*tp_setattr*/ nullptr,
502 /*tp_as_async*/ nullptr,
503 /*tp_repr*/ nullptr,
504 /*tp_as_number*/ nullptr,
505 /*tp_as_sequence*/ nullptr,
506 /*tp_as_mapping*/ nullptr,
507 /*tp_hash*/ nullptr,
508 /*tp_call*/ nullptr,
509 /*tp_str*/ nullptr,
510 /*tp_getattro*/ nullptr,
511 /*tp_setattro*/ nullptr,
512 /*tp_as_buffer*/ nullptr,
513 /*tp_flags*/ Py_TPFLAGS_DEFAULT,
514 /*tp_doc*/ nullptr,
515 /*tp_traverse*/ nullptr,
516 /*tp_clear*/ nullptr,
517 /*tp_richcompare*/ nullptr,
518 /*tp_weaklistoffset*/ 0,
519 /*tp_iter*/ nullptr,
520 /*tp_iternext*/ nullptr,
522 /*tp_members*/ nullptr,
523 /*tp_getset*/ nullptr,
524 /*tp_base*/ nullptr,
525 /*tp_dict*/ nullptr,
526 /*tp_descr_get*/ nullptr,
527 /*tp_descr_set*/ nullptr,
528 /*tp_dictoffset*/ 0,
529 /*tp_init*/ nullptr,
530 /*tp_alloc*/ nullptr,
531 /*tp_new*/ nullptr,
532 /*tp_free*/ nullptr,
533 /*tp_is_gc*/ nullptr,
534 /*tp_bases*/ nullptr,
535 /*tp_mro*/ nullptr,
536 /*tp_cache*/ nullptr,
537 /*tp_subclasses*/ nullptr,
538 /*tp_weaklist*/ nullptr,
539 /*tp_del*/ nullptr,
540 /*tp_version_tag*/ 0,
541 /*tp_finalize*/ nullptr,
542 /*tp_vectorcall*/ nullptr,
543};
544
547/* -------------------------------------------------------------------- */
551static PyObject *bpy_context_temp_override_extract_known_args(const char *const *kwds_static,
552 PyObject *kwds)
553{
554 PyObject *sentinel = Py_Ellipsis;
555 PyObject *kwds_parse = PyDict_New();
556 for (int i = 0; kwds_static[i]; i++) {
557 PyObject *key = PyUnicode_FromString(kwds_static[i]);
558 PyObject *val = _PyDict_Pop(kwds, key, sentinel);
559 if (val != sentinel) {
560 if (PyDict_SetItem(kwds_parse, key, val) == -1) {
562 }
563 }
564 Py_DECREF(key);
565 Py_DECREF(val);
566 }
567 return kwds_parse;
568}
569
570/* NOTE(@ideasman42): `ContextTempOverride` isn't accessible from (without creating an instance),
571 * it should be exposed although it doesn't seem especially important either. */
573 /* Wrap. */
574 bpy_context_temp_override_doc,
575 ".. method:: temp_override(*, window=None, area=None, region=None, **keywords)\n"
576 "\n"
577 " Context manager to temporarily override members in the context.\n"
578 "\n"
579 " :arg window: Window override or None.\n"
580 " :type window: :class:`bpy.types.Window`\n"
581 " :arg screen: Screen override or None.\n"
582 "\n"
583 " .. note:: Switching to or away from full-screen areas & temporary screens "
584 "isn't supported. Passing in these screens will raise an exception, "
585 "actions that leave the context such screens won't restore the prior screen.\n"
586 "\n"
587 " .. note:: Changing the screen has wider implications "
588 "than other arguments as it will also change the works-space "
589 "and potentially the scene (when pinned).\n"
590 "\n"
591 " :type screen: :class:`bpy.types.Screen`\n"
592 " :arg area: Area override or None.\n"
593 " :type area: :class:`bpy.types.Area`\n"
594 " :arg region: Region override or None.\n"
595 " :type region: :class:`bpy.types.Region`\n"
596 " :arg keywords: Additional keywords override context members.\n"
597 " :return: The context manager .\n"
598 " :rtype: ContextTempOverride\n");
599static PyObject *bpy_context_temp_override(PyObject *self, PyObject *args, PyObject *kwds)
600{
601 const PointerRNA *context_ptr = pyrna_struct_as_ptr(self, &RNA_Context);
602 if (context_ptr == nullptr) {
603 return nullptr;
604 }
605
606 if (kwds == nullptr) {
607 /* While this is effectively NOP, support having no keywords as it's more involved
608 * to return an alternative (dummy) context manager. */
609 }
610 else {
611 /* Needed because the keywords copied into `kwds_parse` could contain anything.
612 * As the types of keys aren't checked. */
613 if (!PyArg_ValidateKeywordArguments(kwds)) {
614 return nullptr;
615 }
616 }
617
618 struct {
619 BPy_StructRNA_Parse window;
620 BPy_StructRNA_Parse screen;
622 BPy_StructRNA_Parse region;
623 } params{};
624 params.window.type = &RNA_Window;
625 params.screen.type = &RNA_Screen;
626 params.area.type = &RNA_Area;
627 params.region.type = &RNA_Region;
628
629 static const char *const _keywords[] = {
630 "window",
631 "screen",
632 "area",
633 "region",
634 nullptr,
635 };
636 static _PyArg_Parser _parser = {
638 "|$" /* Optional, keyword only arguments. */
639 "O&" /* `window` */
640 "O&" /* `screen` */
641 "O&" /* `area` */
642 "O&" /* `region` */
643 ":temp_override",
644 _keywords,
645 nullptr,
646 };
647 /* Parse known keywords, the remaining keywords are set using #CTX_py_state_push. */
648 kwds = kwds ? PyDict_Copy(kwds) : PyDict_New();
649 {
650 PyObject *kwds_parse = bpy_context_temp_override_extract_known_args(_keywords, kwds);
651 const int parse_result = _PyArg_ParseTupleAndKeywordsFast(args,
652 kwds_parse,
653 &_parser,
655 &params.window,
657 &params.screen,
659 &params.area,
661 &params.region);
662 Py_DECREF(kwds_parse);
663 if (!parse_result) {
664 Py_DECREF(kwds);
665 return nullptr;
666 }
667 }
668
669 bContext *C = static_cast<bContext *>(context_ptr->data);
670 {
671 /* Merge existing keys that don't exist in the keywords passed in.
672 * This makes it possible to nest context overrides. */
673 PyObject *context_dict_current = static_cast<PyObject *>(CTX_py_dict_get(C));
674 if (context_dict_current != nullptr) {
675 PyDict_Merge(kwds, context_dict_current, 0);
676 }
677 }
678
679 ContextStore ctx_temp = {nullptr};
680 if (params.window.ptr != nullptr) {
681 ctx_temp.win = static_cast<wmWindow *>(params.window.ptr->data);
682 ctx_temp.win_is_set = true;
683 }
684
685 if (params.screen.ptr != nullptr) {
686 ctx_temp.screen = static_cast<bScreen *>(params.screen.ptr->data);
687 ctx_temp.screen_is_set = true;
688 }
689
690 if (params.area.ptr != nullptr) {
691 ctx_temp.area = static_cast<ScrArea *>(params.area.ptr->data);
692 ctx_temp.area_is_set = true;
693 }
694
695 if (params.region.ptr != nullptr) {
696 ctx_temp.region = static_cast<ARegion *>(params.region.ptr->data);
697 ctx_temp.region_is_set = true;
698 }
699
701 ret->context = C;
702 ret->ctx_temp = ctx_temp;
703 memset(&ret->ctx_init, 0, sizeof(ret->ctx_init));
704
705 ret->ctx_temp_orig.screen = nullptr;
706
707 ret->py_state_context_dict = kwds;
708
709 return (PyObject *)ret;
710}
711
714/* -------------------------------------------------------------------- */
718#if (defined(__GNUC__) && !defined(__clang__))
719# pragma GCC diagnostic push
720# pragma GCC diagnostic ignored "-Wcast-function-type"
721#endif
722
724 "temp_override",
725 (PyCFunction)bpy_context_temp_override,
726 METH_VARARGS | METH_KEYWORDS,
727 bpy_context_temp_override_doc,
728};
729
730#if (defined(__GNUC__) && !defined(__clang__))
731# pragma GCC diagnostic pop
732#endif
733
735{
736 if (PyType_Ready(&BPyContextTempOverride_Type) < 0) {
738 return;
739 }
740}
741
void CTX_py_state_push(bContext *C, bContext_PyState *pystate, void *value)
bScreen * CTX_wm_screen(const bContext *C)
void CTX_py_state_pop(bContext *C, bContext_PyState *pystate)
ScrArea * CTX_wm_area(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
void CTX_wm_screen_set(bContext *C, bScreen *screen)
void CTX_wm_window_set(bContext *C, wmWindow *win)
Main * CTX_data_main(const bContext *C)
void CTX_wm_area_set(bContext *C, ScrArea *area)
void CTX_wm_region_set(bContext *C, ARegion *region)
ARegion * CTX_wm_region(const bContext *C)
void * CTX_py_dict_get(const bContext *C)
bool BKE_screen_is_fullscreen_area(const bScreen *screen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition screen.cc:1008
WorkSpaceLayout * BKE_workspace_layout_find_global(const Main *bmain, const bScreen *screen, WorkSpace **r_workspace) ATTR_NONNULL(1
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define LISTBASE_FOREACH(type, var, list)
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define UNUSED_VARS(...)
#define C
Definition RandGen.cpp:29
PyObject * self
const PointerRNA * pyrna_struct_as_ptr(PyObject *py_obj, const StructRNA *srna)
Definition bpy_rna.cc:8177
int pyrna_struct_as_ptr_or_null_parse(PyObject *o, void *p)
Definition bpy_rna.cc:8210
static PyObject * bpy_rna_context_temp_override_enter(BPyContextTempOverride *self)
static PyTypeObject BPyContextTempOverride_Type
static bool wm_check_area_exists(const wmWindow *win, const bScreen *screen, const ScrArea *area)
static PyObject * bpy_context_temp_override(PyObject *self, PyObject *args, PyObject *kwds)
static bool wm_check_region_exists(const bScreen *screen, const ScrArea *area, const ARegion *region)
static bool wm_check_window_exists(const Main *bmain, const wmWindow *win)
static PyObject * bpy_context_temp_override_extract_known_args(const char *const *kwds_static, PyObject *kwds)
static bool wm_check_screen_switch_supported(const bScreen *screen)
static bool wm_check_screen_exists(const Main *bmain, const bScreen *screen)
PyDoc_STRVAR(bpy_context_temp_override_doc, ".. method:: temp_override(*, window=None, area=None, region=None, **keywords)\n" "\n" " Context manager to temporarily override members in the context.\n" "\n" " :arg window: Window override or None.\n" " :type window: :class:`bpy.types.Window`\n" " :arg screen: Screen override or None.\n" "\n" " .. note:: Switching to or away from full-screen areas & temporary screens " "isn't supported. Passing in these screens will raise an exception, " "actions that leave the context such screens won't restore the prior screen.\n" "\n" " .. note:: Changing the screen has wider implications " "than other arguments as it will also change the works-space " "and potentially the scene (when pinned).\n" "\n" " :type screen: :class:`bpy.types.Screen`\n" " :arg area: Area override or None.\n" " :type area: :class:`bpy.types.Area`\n" " :arg region: Region override or None.\n" " :type region: :class:`bpy.types.Region`\n" " :arg keywords: Additional keywords override context members.\n" " :return: The context manager .\n" " :rtype: ContextTempOverride\n")
static PyMethodDef bpy_rna_context_temp_override__tp_methods[]
static PyObject * bpy_rna_context_temp_override_exit(BPyContextTempOverride *self, PyObject *)
void bpy_rna_context_types_init()
static void bpy_rna_context_temp_set_screen_for_window(bContext *C, wmWindow *win, bScreen *screen)
PyMethodDef BPY_rna_context_temp_override_method_def
static void bpy_rna_context_temp_override__tp_dealloc(BPyContextTempOverride *self)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
header-only compatibility defines.
#define PY_ARG_PARSER_HEAD_COMPAT()
return ret
struct BPyContextTempOverride::@1355 ctx_temp_orig
PyObject_HEAD bContext * context
bContext_PyState py_state
ListBase wm
Definition BKE_main.hh:239
ListBase screens
Definition BKE_main.hh:225
void * data
Definition RNA_types.hh:42
ListBase areabase
ScrAreaMap global_areas
void WM_window_set_active_workspace(bContext *C, wmWindow *win, WorkSpace *workspace)
void WM_window_set_active_screen(wmWindow *win, WorkSpace *workspace, bScreen *screen)
bScreen * WM_window_get_active_screen(const wmWindow *win)