Merge branch 'master' into blender2.8
authorCampbell Barton <ideasman42@gmail.com>
Fri, 13 Jul 2018 10:38:24 +0000 (12:38 +0200)
committerCampbell Barton <ideasman42@gmail.com>
Fri, 13 Jul 2018 10:38:46 +0000 (12:38 +0200)
source/blender/windowmanager/CMakeLists.txt
source/blender/windowmanager/intern/wm_init_exit.c
source/blender/windowmanager/intern/wm_menu_type.c [new file with mode: 0644]
source/blender/windowmanager/intern/wm_operator_type.c [new file with mode: 0644]
source/blender/windowmanager/intern/wm_operators.c
source/blender/windowmanager/intern/wm_uilist_type.c [new file with mode: 0644]
source/blender/windowmanager/wm.h

index 8fc46b6ce3f9bfb93080f7e8101a22723659ddc2..eb01332fc2669a287bc6bb25c20d9cdf470a94e1 100644 (file)
@@ -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
index 183e58e5a15c8977d4b6f383d506dbf5b224ce41..6c374f3d8d45dc8dc7f52f7ea3c7fed321bc5676 100644 (file)
@@ -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 (file)
index 0000000..58e8571
--- /dev/null
@@ -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 (file)
index 0000000..e0d3c4a
--- /dev/null
@@ -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);
+}
+
+/** \} */
index 926169e77fdd1883d1b3b1baae92d128d011996f..153cd0809341b90a559b41bc60c9b3b2b6f3db00 100644 (file)
 #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)
 {
@@ -3648,24 +3200,6 @@ static void WM_OT_doc_view_manual_ui_context(wmOperatorType *ot)
        ot->exec = doc_view_manual_ui_context_exec;
 }
 
-/* ******************************************************* */
-
-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 (file)
index 0000000..52619a0
--- /dev/null
@@ -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;
+}
index 3605e57be367e110f4f22d30ea4fd4ade2981ede..d17d5f7d157cf6371d4ba4c46df23f669680c05e 100644 (file)
@@ -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);