Callbacks: exec invoke & modal now use a typed enum wmOperatorStatus. This helps avoid mistakes returning incompatible booleans or other values which don't make sense for operators to return. It also makes it more obvious functions in the WM API are intended to be used to calculate return values for operator callbacks. Operator enums have been moved into DNA_windowmanager_enums.h so this can be used in other headers without loading other includes indirectly. No functional changes expected. Ref !136227
147 lines
3.8 KiB
C++
147 lines
3.8 KiB
C++
/* SPDX-FileCopyrightText: 2008 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup spscript
|
|
*/
|
|
|
|
#include <cstring>
|
|
|
|
#include "BLI_listbase.h"
|
|
|
|
#include "BKE_context.hh"
|
|
#include "BKE_report.hh"
|
|
|
|
#include "BLT_translation.hh"
|
|
|
|
#include "WM_api.hh"
|
|
#include "WM_types.hh"
|
|
#include "wm_event_system.hh"
|
|
|
|
#include "RNA_access.hh"
|
|
#include "RNA_define.hh"
|
|
|
|
#include "ED_screen.hh"
|
|
|
|
#include "script_intern.hh" /* own include */
|
|
|
|
#ifdef WITH_PYTHON
|
|
# include "BPY_extern_run.hh"
|
|
#endif
|
|
|
|
static wmOperatorStatus run_pyfile_exec(bContext *C, wmOperator *op)
|
|
{
|
|
char filepath[FILE_MAX];
|
|
RNA_string_get(op->ptr, "filepath", filepath);
|
|
#ifdef WITH_PYTHON
|
|
if (BPY_run_filepath(C, filepath, op->reports)) {
|
|
ARegion *region = CTX_wm_region(C);
|
|
if (region != nullptr) {
|
|
ED_region_tag_redraw(region);
|
|
}
|
|
return OPERATOR_FINISHED;
|
|
}
|
|
#else
|
|
(void)C; /* unused */
|
|
#endif
|
|
return OPERATOR_CANCELLED; /* FAIL */
|
|
}
|
|
|
|
void SCRIPT_OT_python_file_run(wmOperatorType *ot)
|
|
{
|
|
PropertyRNA *prop;
|
|
|
|
/* identifiers */
|
|
ot->name = "Run Python File";
|
|
ot->description = "Run Python file";
|
|
ot->idname = "SCRIPT_OT_python_file_run";
|
|
|
|
/* api callbacks */
|
|
ot->exec = run_pyfile_exec;
|
|
|
|
/* flags */
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
|
|
|
|
prop = RNA_def_string_file_path(ot->srna, "filepath", nullptr, FILE_MAX, "Path", "");
|
|
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_EDITOR_FILEBROWSER);
|
|
}
|
|
|
|
#ifdef WITH_PYTHON
|
|
static bool script_test_modal_operators(bContext *C)
|
|
{
|
|
wmWindowManager *wm = CTX_wm_manager(C);
|
|
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
|
|
LISTBASE_FOREACH (wmEventHandler *, handler_base, &win->modalhandlers) {
|
|
if (handler_base->type == WM_HANDLER_TYPE_OP) {
|
|
wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base;
|
|
if (handler->op != nullptr) {
|
|
wmOperatorType *ot = handler->op->type;
|
|
if (ot->rna_ext.srna) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
static wmOperatorStatus script_reload_exec(bContext *C, wmOperator *op)
|
|
{
|
|
|
|
#ifdef WITH_PYTHON
|
|
|
|
/* clear running operators */
|
|
if (script_test_modal_operators(C)) {
|
|
BKE_report(op->reports, RPT_ERROR, "Can't reload with running modal operators");
|
|
return OPERATOR_CANCELLED;
|
|
}
|
|
|
|
/* TODO(@ideasman42): this crashes on netrender and keying sets, need to look into why
|
|
* disable for now unless running in debug mode. */
|
|
|
|
/* It would be nice if we could detect when this is called from the Python
|
|
* only postponing in that case, for now always do it. */
|
|
if (true) {
|
|
/* Postpone when called from Python so this can be called from an operator
|
|
* that might be re-registered, crashing Blender when we try to read from the
|
|
* freed operator type which, see #80694. */
|
|
const char *imports[] = {"bpy", nullptr};
|
|
BPY_run_string_exec(C,
|
|
imports,
|
|
"def fn():\n"
|
|
" bpy.utils.load_scripts(reload_scripts=True)\n"
|
|
" return None\n"
|
|
"bpy.app.timers.register(fn)");
|
|
}
|
|
else {
|
|
WM_cursor_wait(true);
|
|
const char *imports[] = {"bpy", nullptr};
|
|
BPY_run_string_eval(C, imports, "bpy.utils.load_scripts(reload_scripts=True)");
|
|
WM_cursor_wait(false);
|
|
}
|
|
|
|
/* Note that #WM_script_tag_reload is called from `bpy.utils.load_scripts`,
|
|
* any additional updates required by this operator should go there. */
|
|
|
|
return OPERATOR_FINISHED;
|
|
#else
|
|
UNUSED_VARS(C, op);
|
|
return OPERATOR_CANCELLED;
|
|
#endif
|
|
}
|
|
|
|
void SCRIPT_OT_reload(wmOperatorType *ot)
|
|
{
|
|
/* identifiers */
|
|
ot->name = "Reload Scripts";
|
|
ot->description = "Reload scripts";
|
|
ot->idname = "SCRIPT_OT_reload";
|
|
|
|
/* api callbacks */
|
|
ot->exec = script_reload_exec;
|
|
}
|