diff options
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/windowmanager/CMakeLists.txt | 9 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_init_exit.c | 2 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_menu_type.c | 105 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_operator_type.c | 546 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_operators.c | 480 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_uilist_type.c | 98 | ||||
-rw-r--r-- | source/blender/windowmanager/wm.h | 1 |
7 files changed, 759 insertions, 482 deletions
diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt index 8fc46b6ce3f..eb01332fc26 100644 --- a/source/blender/windowmanager/CMakeLists.txt +++ b/source/blender/windowmanager/CMakeLists.txt @@ -56,7 +56,6 @@ set(INC_SYS set(SRC intern/wm.c - intern/wm_playanim.c intern/wm_cursors.c intern/wm_dragdrop.c intern/wm_draw.c @@ -68,13 +67,17 @@ set(SRC intern/wm_init_exit.c intern/wm_jobs.c intern/wm_keymap.c + intern/wm_menu_type.c intern/wm_operator_props.c + intern/wm_operator_type.c intern/wm_operators.c - intern/wm_subwindow.c - intern/wm_window.c + intern/wm_playanim.c intern/wm_stereo.c + intern/wm_subwindow.c intern/wm_toolsystem.c intern/wm_tooltip.c + intern/wm_uilist_type.c + intern/wm_window.c manipulators/intern/wm_manipulator.c manipulators/intern/wm_manipulator_group.c manipulators/intern/wm_manipulator_group_type.c diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 183e58e5a15..6c374f3d8d4 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -207,6 +207,8 @@ void WM_init(bContext *C, int argc, const char **argv) BKE_addon_pref_type_init(); wm_operatortype_init(); + wm_operatortypes_register(); + WM_menutype_init(); WM_uilisttype_init(); wm_manipulatortype_init(); diff --git a/source/blender/windowmanager/intern/wm_menu_type.c b/source/blender/windowmanager/intern/wm_menu_type.c new file mode 100644 index 00000000000..58e85716bf1 --- /dev/null +++ b/source/blender/windowmanager/intern/wm_menu_type.c @@ -0,0 +1,105 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/windowmanager/intern/wm_menu_type.c + * \ingroup wm + * + * Menu Registry. + */ + +#include "BLI_sys_types.h" + +#include "DNA_windowmanager_types.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" +#include "BLI_ghash.h" + +#include "BKE_context.h" +#include "BKE_library.h" +#include "BKE_screen.h" + +#include "WM_api.h" +#include "WM_types.h" + +static GHash *menutypes_hash = NULL; + +MenuType *WM_menutype_find(const char *idname, bool quiet) +{ + MenuType *mt; + + if (idname[0]) { + mt = BLI_ghash_lookup(menutypes_hash, idname); + if (mt) + return mt; + } + + if (!quiet) + printf("search for unknown menutype %s\n", idname); + + return NULL; +} + +bool WM_menutype_add(MenuType *mt) +{ + BLI_ghash_insert(menutypes_hash, mt->idname, mt); + return true; +} + +void WM_menutype_freelink(MenuType *mt) +{ + bool ok; + + ok = BLI_ghash_remove(menutypes_hash, mt->idname, NULL, MEM_freeN); + + BLI_assert(ok); + (void)ok; +} + +/* called on initialize WM_init() */ +void WM_menutype_init(void) +{ + /* reserve size is set based on blender default setup */ + menutypes_hash = BLI_ghash_str_new_ex("menutypes_hash gh", 512); +} + +void WM_menutype_free(void) +{ + GHashIterator gh_iter; + + GHASH_ITER (gh_iter, menutypes_hash) { + MenuType *mt = BLI_ghashIterator_getValue(&gh_iter); + if (mt->ext.free) { + mt->ext.free(mt->ext.data); + } + } + + BLI_ghash_free(menutypes_hash, NULL, MEM_freeN); + menutypes_hash = NULL; +} + +bool WM_menutype_poll(bContext *C, MenuType *mt) +{ + if (mt->poll != NULL) { + return mt->poll(C, mt); + } + return true; +} diff --git a/source/blender/windowmanager/intern/wm_operator_type.c b/source/blender/windowmanager/intern/wm_operator_type.c new file mode 100644 index 00000000000..e0d3c4a6727 --- /dev/null +++ b/source/blender/windowmanager/intern/wm_operator_type.c @@ -0,0 +1,546 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/windowmanager/intern/wm_operator_type.c + * \ingroup wm + * + * Operator Registry. + */ + +#include "MEM_guardedalloc.h" + +#include "CLG_log.h" + +#include "DNA_ID.h" +#include "DNA_screen_types.h" +#include "DNA_scene_types.h" +#include "DNA_userdef_types.h" +#include "DNA_windowmanager_types.h" + +#include "BLT_translation.h" + +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" +#include "BLI_ghash.h" + +#include "BKE_context.h" +#include "BKE_idprop.h" +#include "BKE_library.h" + +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "wm.h" +#include "wm_event_system.h" + +#define UNDOCUMENTED_OPERATOR_TIP N_("(undocumented operator)") + +static void wm_operatortype_free_macro(wmOperatorType *ot); + +/* -------------------------------------------------------------------- */ +/** \name Operator Type Registry + * \{ */ + +static GHash *global_ops_hash = NULL; +/** Counter for operator-properties that should not be tagged with #OP_PROP_TAG_ADVANCED. */ +static int ot_prop_basic_count = -1; + +wmOperatorType *WM_operatortype_find(const char *idname, bool quiet) +{ + if (idname[0]) { + wmOperatorType *ot; + + /* needed to support python style names without the _OT_ syntax */ + char idname_bl[OP_MAX_TYPENAME]; + WM_operator_bl_idname(idname_bl, idname); + + ot = BLI_ghash_lookup(global_ops_hash, idname_bl); + if (ot) { + return ot; + } + + if (!quiet) { + CLOG_INFO(WM_LOG_OPERATORS, 0, "search for unknown operator '%s', '%s'\n", idname_bl, idname); + } + } + else { + if (!quiet) { + CLOG_INFO(WM_LOG_OPERATORS, 0, "search for empty operator"); + } + } + + return NULL; +} + +/* caller must free */ +void WM_operatortype_iter(GHashIterator *ghi) +{ + BLI_ghashIterator_init(ghi, global_ops_hash); +} + +/** \name Operator Type Append + * \{ */ + +static wmOperatorType *wm_operatortype_append__begin(void) +{ + wmOperatorType *ot = MEM_callocN(sizeof(wmOperatorType), "operatortype"); + + BLI_assert(ot_prop_basic_count == -1); + + ot->srna = RNA_def_struct_ptr(&BLENDER_RNA, "", &RNA_OperatorProperties); + RNA_def_struct_property_tags(ot->srna, rna_enum_operator_property_tags); + /* Set the default i18n context now, so that opfunc can redefine it if needed! */ + RNA_def_struct_translation_context(ot->srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT); + ot->translation_context = BLT_I18NCONTEXT_OPERATOR_DEFAULT; + + return ot; +} +static void wm_operatortype_append__end(wmOperatorType *ot) +{ + if (ot->name == NULL) { + CLOG_ERROR(WM_LOG_OPERATORS, "Operator '%s' has no name property", ot->idname); + } + + /* Allow calling _begin without _end in operatortype creation. */ + WM_operatortype_props_advanced_end(ot); + + /* XXX All ops should have a description but for now allow them not to. */ + RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description : UNDOCUMENTED_OPERATOR_TIP); + RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname); + + BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot); +} + +/* all ops in 1 list (for time being... needs evaluation later) */ +void WM_operatortype_append(void (*opfunc)(wmOperatorType *)) +{ + wmOperatorType *ot = wm_operatortype_append__begin(); + opfunc(ot); + wm_operatortype_append__end(ot); +} + +void WM_operatortype_append_ptr(void (*opfunc)(wmOperatorType *, void *), void *userdata) +{ + wmOperatorType *ot = wm_operatortype_append__begin(); + opfunc(ot, userdata); + wm_operatortype_append__end(ot); +} + +/** \} */ + + +/* called on initialize WM_exit() */ +void WM_operatortype_remove_ptr(wmOperatorType *ot) +{ + BLI_assert(ot == WM_operatortype_find(ot->idname, false)); + + RNA_struct_free(&BLENDER_RNA, ot->srna); + + if (ot->last_properties) { + IDP_FreeProperty(ot->last_properties); + MEM_freeN(ot->last_properties); + } + + if (ot->macro.first) + wm_operatortype_free_macro(ot); + + BLI_ghash_remove(global_ops_hash, ot->idname, NULL, NULL); + + WM_keyconfig_update_operatortype(); + + MEM_freeN(ot); +} + +bool WM_operatortype_remove(const char *idname) +{ + wmOperatorType *ot = WM_operatortype_find(idname, 0); + + if (ot == NULL) + return false; + + WM_operatortype_remove_ptr(ot); + + return true; +} + +/* called on initialize WM_init() */ +void wm_operatortype_init(void) +{ + /* reserve size is set based on blender default setup */ + global_ops_hash = BLI_ghash_str_new_ex("wm_operatortype_init gh", 2048); +} + +static void operatortype_ghash_free_cb(wmOperatorType *ot) +{ + if (ot->last_properties) { + IDP_FreeProperty(ot->last_properties); + MEM_freeN(ot->last_properties); + } + + if (ot->macro.first) + wm_operatortype_free_macro(ot); + + if (ot->ext.srna) /* python operator, allocs own string */ + MEM_freeN((void *)ot->idname); + + MEM_freeN(ot); +} + +void wm_operatortype_free(void) +{ + BLI_ghash_free(global_ops_hash, NULL, (GHashValFreeFP)operatortype_ghash_free_cb); + global_ops_hash = NULL; +} + +/** + * Tag all operator-properties of \a ot defined after calling this, until + * the next #WM_operatortype_props_advanced_end call (if available), with + * #OP_PROP_TAG_ADVANCED. Previously defined ones properties not touched. + * + * Calling this multiple times without a call to #WM_operatortype_props_advanced_end, + * all calls after the first one are ignored. Meaning all propereties defined after the + * first call are tagged as advanced. + * + * This doesn't do the actual tagging, #WM_operatortype_props_advanced_end does which is + * called for all operators during registration (see #wm_operatortype_append__end). + */ +void WM_operatortype_props_advanced_begin(wmOperatorType *ot) +{ + if (ot_prop_basic_count == -1) { /* Don't do anything if _begin was called before, but not _end */ + ot_prop_basic_count = RNA_struct_count_properties(ot->srna); + } +} + +/** + * Tags all operator-properties of \ot defined since the first #WM_operatortype_props_advanced_begin + * call, or the last #WM_operatortype_props_advanced_end call, with #OP_PROP_TAG_ADVANCED. + * Note that this is called for all operators during registration (see #wm_operatortype_append__end). + * So it does not need to be explicitly called in operator-type definition. + */ +void WM_operatortype_props_advanced_end(wmOperatorType *ot) +{ + PointerRNA struct_ptr; + int counter = 0; + + if (ot_prop_basic_count == -1) { + /* WM_operatortype_props_advanced_begin was not called. Don't do anything. */ + return; + } + + RNA_pointer_create(NULL, ot->srna, NULL, &struct_ptr); + + RNA_STRUCT_BEGIN (&struct_ptr, prop) + { + counter++; + if (counter > ot_prop_basic_count) { + WM_operatortype_prop_tag(prop, OP_PROP_TAG_ADVANCED); + } + } + RNA_STRUCT_END; + + ot_prop_basic_count = -1; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Operator Macro Type + * \{ */ + +typedef struct { + int retval; +} MacroData; + +static void wm_macro_start(wmOperator *op) +{ + if (op->customdata == NULL) { + op->customdata = MEM_callocN(sizeof(MacroData), "MacroData"); + } +} + +static int wm_macro_end(wmOperator *op, int retval) +{ + if (retval & OPERATOR_CANCELLED) { + MacroData *md = op->customdata; + + if (md->retval & OPERATOR_FINISHED) { + retval |= OPERATOR_FINISHED; + retval &= ~OPERATOR_CANCELLED; + } + } + + /* if modal is ending, free custom data */ + if (retval & (OPERATOR_FINISHED | OPERATOR_CANCELLED)) { + if (op->customdata) { + MEM_freeN(op->customdata); + op->customdata = NULL; + } + } + + return retval; +} + +/* macro exec only runs exec calls */ +static int wm_macro_exec(bContext *C, wmOperator *op) +{ + wmOperator *opm; + int retval = OPERATOR_FINISHED; + + wm_macro_start(op); + + for (opm = op->macro.first; opm; opm = opm->next) { + + if (opm->type->exec) { + retval = opm->type->exec(C, opm); + OPERATOR_RETVAL_CHECK(retval); + + if (retval & OPERATOR_FINISHED) { + MacroData *md = op->customdata; + md->retval = OPERATOR_FINISHED; /* keep in mind that at least one operator finished */ + } + else { + break; /* operator didn't finish, end macro */ + } + } + else { + CLOG_WARN(WM_LOG_OPERATORS, "'%s' cant exec macro", opm->type->idname); + } + } + + return wm_macro_end(op, retval); +} + +static int wm_macro_invoke_internal(bContext *C, wmOperator *op, const wmEvent *event, wmOperator *opm) +{ + int retval = OPERATOR_FINISHED; + + /* start from operator received as argument */ + for (; opm; opm = opm->next) { + if (opm->type->invoke) + retval = opm->type->invoke(C, opm, event); + else if (opm->type->exec) + retval = opm->type->exec(C, opm); + + OPERATOR_RETVAL_CHECK(retval); + + BLI_movelisttolist(&op->reports->list, &opm->reports->list); + + if (retval & OPERATOR_FINISHED) { + MacroData *md = op->customdata; + md->retval = OPERATOR_FINISHED; /* keep in mind that at least one operator finished */ + } + else { + break; /* operator didn't finish, end macro */ + } + } + + return wm_macro_end(op, retval); +} + +static int wm_macro_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + wm_macro_start(op); + return wm_macro_invoke_internal(C, op, event, op->macro.first); +} + +static int wm_macro_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + wmOperator *opm = op->opm; + int retval = OPERATOR_FINISHED; + + if (opm == NULL) { + CLOG_ERROR(WM_LOG_OPERATORS, "macro error, calling NULL modal()"); + } + else { + retval = opm->type->modal(C, opm, event); + OPERATOR_RETVAL_CHECK(retval); + + /* if we're halfway through using a tool and cancel it, clear the options [#37149] */ + if (retval & OPERATOR_CANCELLED) { + WM_operator_properties_clear(opm->ptr); + } + + /* if this one is done but it's not the last operator in the macro */ + if ((retval & OPERATOR_FINISHED) && opm->next) { + MacroData *md = op->customdata; + + md->retval = OPERATOR_FINISHED; /* keep in mind that at least one operator finished */ + + retval = wm_macro_invoke_internal(C, op, event, opm->next); + + /* if new operator is modal and also added its own handler */ + if (retval & OPERATOR_RUNNING_MODAL && op->opm != opm) { + wmWindow *win = CTX_wm_window(C); + wmEventHandler *handler; + + handler = BLI_findptr(&win->modalhandlers, op, offsetof(wmEventHandler, op)); + if (handler) { + BLI_remlink(&win->modalhandlers, handler); + wm_event_free_handler(handler); + } + + /* if operator is blocking, grab cursor + * This may end up grabbing twice, but we don't care. + * */ + if (op->opm->type->flag & OPTYPE_BLOCKING) { + int bounds[4] = {-1, -1, -1, -1}; + const bool wrap = ( + (U.uiflag & USER_CONTINUOUS_MOUSE) && + ((op->opm->flag & OP_IS_MODAL_GRAB_CURSOR) || (op->opm->type->flag & OPTYPE_GRAB_CURSOR))); + + if (wrap) { + ARegion *ar = CTX_wm_region(C); + if (ar) { + bounds[0] = ar->winrct.xmin; + bounds[1] = ar->winrct.ymax; + bounds[2] = ar->winrct.xmax; + bounds[3] = ar->winrct.ymin; + } + } + + WM_cursor_grab_enable(win, wrap, false, bounds); + } + } + } + } + + return wm_macro_end(op, retval); +} + +static void wm_macro_cancel(bContext *C, wmOperator *op) +{ + /* call cancel on the current modal operator, if any */ + if (op->opm && op->opm->type->cancel) { + op->opm->type->cancel(C, op->opm); + } + + wm_macro_end(op, OPERATOR_CANCELLED); +} + +/* Names have to be static for now */ +wmOperatorType *WM_operatortype_append_macro(const char *idname, const char *name, const char *description, int flag) +{ + wmOperatorType *ot; + const char *i18n_context; + + if (WM_operatortype_find(idname, true)) { + CLOG_ERROR(WM_LOG_OPERATORS, "operator %s exists, cannot create macro", idname); + return NULL; + } + + ot = MEM_callocN(sizeof(wmOperatorType), "operatortype"); + ot->srna = RNA_def_struct_ptr(&BLENDER_RNA, "", &RNA_OperatorProperties); + + ot->idname = idname; + ot->name = name; + ot->description = description; + ot->flag = OPTYPE_MACRO | flag; + + ot->exec = wm_macro_exec; + ot->invoke = wm_macro_invoke; + ot->modal = wm_macro_modal; + ot->cancel = wm_macro_cancel; + ot->poll = NULL; + + if (!ot->description) /* XXX All ops should have a description but for now allow them not to. */ + ot->description = UNDOCUMENTED_OPERATOR_TIP; + + RNA_def_struct_ui_text(ot->srna, ot->name, ot->description); + RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname); + /* Use i18n context from ext.srna if possible (py operators). */ + i18n_context = ot->ext.srna ? RNA_struct_translation_context(ot->ext.srna) : BLT_I18NCONTEXT_OPERATOR_DEFAULT; + RNA_def_struct_translation_context(ot->srna, i18n_context); + ot->translation_context = i18n_context; + + BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot); + + return ot; +} + +void WM_operatortype_append_macro_ptr(void (*opfunc)(wmOperatorType *, void *), void *userdata) +{ + wmOperatorType *ot; + + ot = MEM_callocN(sizeof(wmOperatorType), "operatortype"); + ot->srna = RNA_def_struct_ptr(&BLENDER_RNA, "", &RNA_OperatorProperties); + + ot->flag = OPTYPE_MACRO; + ot->exec = wm_macro_exec; + ot->invoke = wm_macro_invoke; + ot->modal = wm_macro_modal; + ot->cancel = wm_macro_cancel; + ot->poll = NULL; + + if (!ot->description) + ot->description = UNDOCUMENTED_OPERATOR_TIP; + + /* Set the default i18n context now, so that opfunc can redefine it if needed! */ + RNA_def_struct_translation_context(ot->srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT); + ot->translation_context = BLT_I18NCONTEXT_OPERATOR_DEFAULT; + opfunc(ot, userdata); + + RNA_def_struct_ui_text(ot->srna, ot->name, ot->description); + RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname); + + BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot); +} + +wmOperatorTypeMacro *WM_operatortype_macro_define(wmOperatorType *ot, const char *idname) +{ + wmOperatorTypeMacro *otmacro = MEM_callocN(sizeof(wmOperatorTypeMacro), "wmOperatorTypeMacro"); + + BLI_strncpy(otmacro->idname, idname, OP_MAX_TYPENAME); + + /* do this on first use, since operatordefinitions might have been not done yet */ + WM_operator_properties_alloc(&(otmacro->ptr), &(otmacro->properties), idname); + WM_operator_properties_sanitize(otmacro->ptr, 1); + + BLI_addtail(&ot->macro, otmacro); + + { + /* operator should always be found but in the event its not. don't segfault */ + wmOperatorType *otsub = WM_operatortype_find(idname, 0); + if (otsub) { + RNA_def_pointer_runtime(ot->srna, otsub->idname, otsub->srna, + otsub->name, otsub->description); + } + } + + return otmacro; +} + +static void wm_operatortype_free_macro(wmOperatorType *ot) +{ + wmOperatorTypeMacro *otmacro; + + for (otmacro = ot->macro.first; otmacro; otmacro = otmacro->next) { + if (otmacro->ptr) { + WM_operator_properties_free(otmacro->ptr); + MEM_freeN(otmacro->ptr); + } + } + BLI_freelistN(&ot->macro); +} + +/** \} */ diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 926169e77fd..153cd080934 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -120,408 +120,9 @@ #include "wm_files.h" #include "wm_window.h" -static GHash *global_ops_hash = NULL; -/** Counter for operator-properties that should not be tagged with #OP_PROP_TAG_ADVANCED. */ -static int ot_prop_basic_count = -1; - #define UNDOCUMENTED_OPERATOR_TIP N_("(undocumented operator)") /* ************ operator API, exported ********** */ - - -wmOperatorType *WM_operatortype_find(const char *idname, bool quiet) -{ - if (idname[0]) { - wmOperatorType *ot; - - /* needed to support python style names without the _OT_ syntax */ - char idname_bl[OP_MAX_TYPENAME]; - WM_operator_bl_idname(idname_bl, idname); - - ot = BLI_ghash_lookup(global_ops_hash, idname_bl); - if (ot) { - return ot; - } - - if (!quiet) { - CLOG_INFO(WM_LOG_OPERATORS, 0, "search for unknown operator '%s', '%s'\n", idname_bl, idname); - } - } - else { - if (!quiet) { - CLOG_INFO(WM_LOG_OPERATORS, 0, "search for empty operator"); - } - } - - return NULL; -} - -/* caller must free */ -void WM_operatortype_iter(GHashIterator *ghi) -{ - BLI_ghashIterator_init(ghi, global_ops_hash); -} - -/** \name Operator Type Append - * \{ */ - -static wmOperatorType *wm_operatortype_append__begin(void) -{ - wmOperatorType *ot = MEM_callocN(sizeof(wmOperatorType), "operatortype"); - - BLI_assert(ot_prop_basic_count == -1); - - ot->srna = RNA_def_struct_ptr(&BLENDER_RNA, "", &RNA_OperatorProperties); - RNA_def_struct_property_tags(ot->srna, rna_enum_operator_property_tags); - /* Set the default i18n context now, so that opfunc can redefine it if needed! */ - RNA_def_struct_translation_context(ot->srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT); - ot->translation_context = BLT_I18NCONTEXT_OPERATOR_DEFAULT; - - return ot; -} -static void wm_operatortype_append__end(wmOperatorType *ot) -{ - if (ot->name == NULL) { - CLOG_ERROR(WM_LOG_OPERATORS, "Operator '%s' has no name property", ot->idname); - } - - /* Allow calling _begin without _end in operatortype creation. */ - WM_operatortype_props_advanced_end(ot); - - /* XXX All ops should have a description but for now allow them not to. */ - RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description : UNDOCUMENTED_OPERATOR_TIP); - RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname); - - BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot); -} - -/* all ops in 1 list (for time being... needs evaluation later) */ -void WM_operatortype_append(void (*opfunc)(wmOperatorType *)) -{ - wmOperatorType *ot = wm_operatortype_append__begin(); - opfunc(ot); - wm_operatortype_append__end(ot); -} - -void WM_operatortype_append_ptr(void (*opfunc)(wmOperatorType *, void *), void *userdata) -{ - wmOperatorType *ot = wm_operatortype_append__begin(); - opfunc(ot, userdata); - wm_operatortype_append__end(ot); -} - -/** \} */ - -/* ********************* macro operator ******************** */ - -typedef struct { - int retval; -} MacroData; - -static void wm_macro_start(wmOperator *op) -{ - if (op->customdata == NULL) { - op->customdata = MEM_callocN(sizeof(MacroData), "MacroData"); - } -} - -static int wm_macro_end(wmOperator *op, int retval) -{ - if (retval & OPERATOR_CANCELLED) { - MacroData *md = op->customdata; - - if (md->retval & OPERATOR_FINISHED) { - retval |= OPERATOR_FINISHED; - retval &= ~OPERATOR_CANCELLED; - } - } - - /* if modal is ending, free custom data */ - if (retval & (OPERATOR_FINISHED | OPERATOR_CANCELLED)) { - if (op->customdata) { - MEM_freeN(op->customdata); - op->customdata = NULL; - } - } - - return retval; -} - -/* macro exec only runs exec calls */ -static int wm_macro_exec(bContext *C, wmOperator *op) -{ - wmOperator *opm; - int retval = OPERATOR_FINISHED; - - wm_macro_start(op); - - for (opm = op->macro.first; opm; opm = opm->next) { - - if (opm->type->exec) { - retval = opm->type->exec(C, opm); - OPERATOR_RETVAL_CHECK(retval); - - if (retval & OPERATOR_FINISHED) { - MacroData *md = op->customdata; - md->retval = OPERATOR_FINISHED; /* keep in mind that at least one operator finished */ - } - else { - break; /* operator didn't finish, end macro */ - } - } - else { - CLOG_WARN(WM_LOG_OPERATORS, "'%s' cant exec macro", opm->type->idname); - } - } - - return wm_macro_end(op, retval); -} - -static int wm_macro_invoke_internal(bContext *C, wmOperator *op, const wmEvent *event, wmOperator *opm) -{ - int retval = OPERATOR_FINISHED; - - /* start from operator received as argument */ - for (; opm; opm = opm->next) { - if (opm->type->invoke) - retval = opm->type->invoke(C, opm, event); - else if (opm->type->exec) - retval = opm->type->exec(C, opm); - - OPERATOR_RETVAL_CHECK(retval); - - BLI_movelisttolist(&op->reports->list, &opm->reports->list); - - if (retval & OPERATOR_FINISHED) { - MacroData *md = op->customdata; - md->retval = OPERATOR_FINISHED; /* keep in mind that at least one operator finished */ - } - else { - break; /* operator didn't finish, end macro */ - } - } - - return wm_macro_end(op, retval); -} - -static int wm_macro_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - wm_macro_start(op); - return wm_macro_invoke_internal(C, op, event, op->macro.first); -} - -static int wm_macro_modal(bContext *C, wmOperator *op, const wmEvent *event) -{ - wmOperator *opm = op->opm; - int retval = OPERATOR_FINISHED; - - if (opm == NULL) { - CLOG_ERROR(WM_LOG_OPERATORS, "macro error, calling NULL modal()"); - } - else { - retval = opm->type->modal(C, opm, event); - OPERATOR_RETVAL_CHECK(retval); - - /* if we're halfway through using a tool and cancel it, clear the options [#37149] */ - if (retval & OPERATOR_CANCELLED) { - WM_operator_properties_clear(opm->ptr); - } - - /* if this one is done but it's not the last operator in the macro */ - if ((retval & OPERATOR_FINISHED) && opm->next) { - MacroData *md = op->customdata; - - md->retval = OPERATOR_FINISHED; /* keep in mind that at least one operator finished */ - - retval = wm_macro_invoke_internal(C, op, event, opm->next); - - /* if new operator is modal and also added its own handler */ - if (retval & OPERATOR_RUNNING_MODAL && op->opm != opm) { - wmWindow *win = CTX_wm_window(C); - wmEventHandler *handler; - - handler = BLI_findptr(&win->modalhandlers, op, offsetof(wmEventHandler, op)); - if (handler) { - BLI_remlink(&win->modalhandlers, handler); - wm_event_free_handler(handler); - } - - /* if operator is blocking, grab cursor - * This may end up grabbing twice, but we don't care. - * */ - if (op->opm->type->flag & OPTYPE_BLOCKING) { - int bounds[4] = {-1, -1, -1, -1}; - const bool wrap = ( - (U.uiflag & USER_CONTINUOUS_MOUSE) && - ((op->opm->flag & OP_IS_MODAL_GRAB_CURSOR) || (op->opm->type->flag & OPTYPE_GRAB_CURSOR))); - - if (wrap) { - ARegion *ar = CTX_wm_region(C); - if (ar) { - bounds[0] = ar->winrct.xmin; - bounds[1] = ar->winrct.ymax; - bounds[2] = ar->winrct.xmax; - bounds[3] = ar->winrct.ymin; - } - } - - WM_cursor_grab_enable(win, wrap, false, bounds); - } - } - } - } - - return wm_macro_end(op, retval); -} - -static void wm_macro_cancel(bContext *C, wmOperator *op) -{ - /* call cancel on the current modal operator, if any */ - if (op->opm && op->opm->type->cancel) { - op->opm->type->cancel(C, op->opm); - } - - wm_macro_end(op, OPERATOR_CANCELLED); -} - -/* Names have to be static for now */ -wmOperatorType *WM_operatortype_append_macro(const char *idname, const char *name, const char *description, int flag) -{ - wmOperatorType *ot; - const char *i18n_context; - - if (WM_operatortype_find(idname, true)) { - CLOG_ERROR(WM_LOG_OPERATORS, "operator %s exists, cannot create macro", idname); - return NULL; - } - - ot = MEM_callocN(sizeof(wmOperatorType), "operatortype"); - ot->srna = RNA_def_struct_ptr(&BLENDER_RNA, "", &RNA_OperatorProperties); - - ot->idname = idname; - ot->name = name; - ot->description = description; - ot->flag = OPTYPE_MACRO | flag; - - ot->exec = wm_macro_exec; - ot->invoke = wm_macro_invoke; - ot->modal = wm_macro_modal; - ot->cancel = wm_macro_cancel; - ot->poll = NULL; - - if (!ot->description) /* XXX All ops should have a description but for now allow them not to. */ - ot->description = UNDOCUMENTED_OPERATOR_TIP; - - RNA_def_struct_ui_text(ot->srna, ot->name, ot->description); - RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname); - /* Use i18n context from ext.srna if possible (py operators). */ - i18n_context = ot->ext.srna ? RNA_struct_translation_context(ot->ext.srna) : BLT_I18NCONTEXT_OPERATOR_DEFAULT; - RNA_def_struct_translation_context(ot->srna, i18n_context); - ot->translation_context = i18n_context; - - BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot); - - return ot; -} - -void WM_operatortype_append_macro_ptr(void (*opfunc)(wmOperatorType *, void *), void *userdata) -{ - wmOperatorType *ot; - - ot = MEM_callocN(sizeof(wmOperatorType), "operatortype"); - ot->srna = RNA_def_struct_ptr(&BLENDER_RNA, "", &RNA_OperatorProperties); - - ot->flag = OPTYPE_MACRO; - ot->exec = wm_macro_exec; - ot->invoke = wm_macro_invoke; - ot->modal = wm_macro_modal; - ot->cancel = wm_macro_cancel; - ot->poll = NULL; - - if (!ot->description) - ot->description = UNDOCUMENTED_OPERATOR_TIP; - - /* Set the default i18n context now, so that opfunc can redefine it if needed! */ - RNA_def_struct_translation_context(ot->srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT); - ot->translation_context = BLT_I18NCONTEXT_OPERATOR_DEFAULT; - opfunc(ot, userdata); - - RNA_def_struct_ui_text(ot->srna, ot->name, ot->description); - RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname); - - BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot); -} - -wmOperatorTypeMacro *WM_operatortype_macro_define(wmOperatorType *ot, const char *idname) -{ - wmOperatorTypeMacro *otmacro = MEM_callocN(sizeof(wmOperatorTypeMacro), "wmOperatorTypeMacro"); - - BLI_strncpy(otmacro->idname, idname, OP_MAX_TYPENAME); - - /* do this on first use, since operatordefinitions might have been not done yet */ - WM_operator_properties_alloc(&(otmacro->ptr), &(otmacro->properties), idname); - WM_operator_properties_sanitize(otmacro->ptr, 1); - - BLI_addtail(&ot->macro, otmacro); - - { - /* operator should always be found but in the event its not. don't segfault */ - wmOperatorType *otsub = WM_operatortype_find(idname, 0); - if (otsub) { - RNA_def_pointer_runtime(ot->srna, otsub->idname, otsub->srna, - otsub->name, otsub->description); - } - } - - return otmacro; -} - -static void wm_operatortype_free_macro(wmOperatorType *ot) -{ - wmOperatorTypeMacro *otmacro; - - for (otmacro = ot->macro.first; otmacro; otmacro = otmacro->next) { - if (otmacro->ptr) { - WM_operator_properties_free(otmacro->ptr); - MEM_freeN(otmacro->ptr); - } - } - BLI_freelistN(&ot->macro); -} - -void WM_operatortype_remove_ptr(wmOperatorType *ot) -{ - BLI_assert(ot == WM_operatortype_find(ot->idname, false)); - - RNA_struct_free(&BLENDER_RNA, ot->srna); - - if (ot->last_properties) { - IDP_FreeProperty(ot->last_properties); - MEM_freeN(ot->last_properties); - } - - if (ot->macro.first) - wm_operatortype_free_macro(ot); - - BLI_ghash_remove(global_ops_hash, ot->idname, NULL, NULL); - - WM_keyconfig_update_operatortype(); - - MEM_freeN(ot); -} - -bool WM_operatortype_remove(const char *idname) -{ - wmOperatorType *ot = WM_operatortype_find(idname, 0); - - if (ot == NULL) - return false; - - WM_operatortype_remove_ptr(ot); - - return true; -} - /** * Remove memory of all previously executed tools. */ @@ -543,55 +144,6 @@ void WM_operatortype_last_properties_clear_all(void) } } -/** - * Tag all operator-properties of \a ot defined after calling this, until - * the next #WM_operatortype_props_advanced_end call (if available), with - * #OP_PROP_TAG_ADVANCED. Previously defined ones properties not touched. - * - * Calling this multiple times without a call to #WM_operatortype_props_advanced_end, - * all calls after the first one are ignored. Meaning all propereties defined after the - * first call are tagged as advanced. - * - * This doesn't do the actual tagging, #WM_operatortype_props_advanced_end does which is - * called for all operators during registration (see #wm_operatortype_append__end). - */ -void WM_operatortype_props_advanced_begin(wmOperatorType *ot) -{ - if (ot_prop_basic_count == -1) { /* Don't do anything if _begin was called before, but not _end */ - ot_prop_basic_count = RNA_struct_count_properties(ot->srna); - } -} - -/** - * Tags all operator-properties of \ot defined since the first #WM_operatortype_props_advanced_begin - * call, or the last #WM_operatortype_props_advanced_end call, with #OP_PROP_TAG_ADVANCED. - * Note that this is called for all operators during registration (see #wm_operatortype_append__end). - * So it does not need to be explicitly called in operator-type definition. - */ -void WM_operatortype_props_advanced_end(wmOperatorType *ot) -{ - PointerRNA struct_ptr; - int counter = 0; - - if (ot_prop_basic_count == -1) { - /* WM_operatortype_props_advanced_begin was not called. Don't do anything. */ - return; - } - - RNA_pointer_create(NULL, ot->srna, NULL, &struct_ptr); - - RNA_STRUCT_BEGIN (&struct_ptr, prop) - { - counter++; - if (counter > ot_prop_basic_count) { - WM_operatortype_prop_tag(prop, OP_PROP_TAG_ADVANCED); - } - } - RNA_STRUCT_END; - - ot_prop_basic_count = -1; -} - /* SOME_OT_op -> some.op */ void WM_operator_py_idname(char *to, const char *from) { @@ -3649,24 +3201,6 @@ static void WM_OT_doc_view_manual_ui_context(wmOperatorType *ot) } /* ******************************************************* */ - -static void operatortype_ghash_free_cb(wmOperatorType *ot) -{ - if (ot->last_properties) { - IDP_FreeProperty(ot->last_properties); - MEM_freeN(ot->last_properties); - } - - if (ot->macro.first) - wm_operatortype_free_macro(ot); - - if (ot->ext.srna) /* python operator, allocs own string */ - MEM_freeN((void *)ot->idname); - - MEM_freeN(ot); -} - -/* ******************************************************* */ /* toggle 3D for current window, turning it fullscreen if needed */ static void WM_OT_stereo3d_set(wmOperatorType *ot) { @@ -3697,20 +3231,8 @@ static void WM_OT_stereo3d_set(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -/* ******************************************************* */ -/* called on initialize WM_exit() */ -void wm_operatortype_free(void) -{ - BLI_ghash_free(global_ops_hash, NULL, (GHashValFreeFP)operatortype_ghash_free_cb); - global_ops_hash = NULL; -} - -/* called on initialize WM_init() */ -void wm_operatortype_init(void) +void wm_operatortypes_register(void) { - /* reserve size is set based on blender default setup */ - global_ops_hash = BLI_ghash_str_new_ex("wm_operatortype_init gh", 2048); - WM_operatortype_append(WM_OT_window_close); WM_operatortype_append(WM_OT_window_new); WM_operatortype_append(WM_OT_window_new_main); diff --git a/source/blender/windowmanager/intern/wm_uilist_type.c b/source/blender/windowmanager/intern/wm_uilist_type.c new file mode 100644 index 00000000000..52619a09218 --- /dev/null +++ b/source/blender/windowmanager/intern/wm_uilist_type.c @@ -0,0 +1,98 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/windowmanager/intern/wm_uilist_type.c + * \ingroup wm + * + * UI List Registry. + */ + +#include "BLI_sys_types.h" + +#include "DNA_windowmanager_types.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" +#include "BLI_ghash.h" + +#include "BKE_context.h" +#include "BKE_library.h" +#include "BKE_screen.h" + +#include "WM_api.h" +#include "WM_types.h" + +static GHash *uilisttypes_hash = NULL; + +uiListType *WM_uilisttype_find(const char *idname, bool quiet) +{ + uiListType *ult; + + if (idname[0]) { + ult = BLI_ghash_lookup(uilisttypes_hash, idname); + if (ult) { + return ult; + } + } + + if (!quiet) { + printf("search for unknown uilisttype %s\n", idname); + } + + return NULL; +} + +bool WM_uilisttype_add(uiListType *ult) +{ + BLI_ghash_insert(uilisttypes_hash, ult->idname, ult); + return 1; +} + +void WM_uilisttype_freelink(uiListType *ult) +{ + bool ok; + + ok = BLI_ghash_remove(uilisttypes_hash, ult->idname, NULL, MEM_freeN); + + BLI_assert(ok); + (void)ok; +} + +/* called on initialize WM_init() */ +void WM_uilisttype_init(void) +{ + uilisttypes_hash = BLI_ghash_str_new_ex("uilisttypes_hash gh", 16); +} + +void WM_uilisttype_free(void) +{ + GHashIterator gh_iter; + + GHASH_ITER (gh_iter, uilisttypes_hash) { + uiListType *ult = BLI_ghashIterator_getValue(&gh_iter); + if (ult->ext.free) { + ult->ext.free(ult->ext.data); + } + } + + BLI_ghash_free(uilisttypes_hash, NULL, MEM_freeN); + uilisttypes_hash = NULL; +} diff --git a/source/blender/windowmanager/wm.h b/source/blender/windowmanager/wm.h index 3605e57be36..d17d5f7d157 100644 --- a/source/blender/windowmanager/wm.h +++ b/source/blender/windowmanager/wm.h @@ -62,6 +62,7 @@ void wm_operator_register(bContext *C, wmOperator *op); void wm_operatortype_free(void); void wm_operatortype_init(void); void wm_window_keymap(wmKeyConfig *keyconf); +void wm_operatortypes_register(void); /* wm_gesture.c */ void wm_gesture_draw(struct wmWindow *win); |