Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/blenloader/intern/readfile.c1
-rw-r--r--source/blender/makesdna/DNA_windowmanager_types.h2
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c149
3 files changed, 97 insertions, 55 deletions
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index b0e68c81c73..26492ed490c 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -4540,6 +4540,7 @@ static void direct_link_windowmanager(FileData *fd, wmWindowManager *wm)
wm->windrawable= NULL;
wm->initialized= 0;
+ wm->op_undo_depth= 0;
}
static void lib_link_windowmanager(FileData *fd, Main *main)
diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h
index 4a7080034ee..f520a3d5fb2 100644
--- a/source/blender/makesdna/DNA_windowmanager_types.h
+++ b/source/blender/makesdna/DNA_windowmanager_types.h
@@ -109,7 +109,7 @@ typedef struct wmWindowManager {
int initialized; /* set on file read */
short file_saved; /* indicator whether data was saved */
- short pad;
+ short op_undo_depth; /* operator stack depth to avoid nested undo pushes */
ListBase operators; /* operator registry */
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index f508062f702..dc4eec7f5e6 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -303,9 +303,37 @@ int WM_operator_poll(bContext *C, wmOperatorType *ot)
return 1;
}
+static void wm_operator_finished(bContext *C, wmOperator *op, int repeat)
+{
+ wmWindowManager *wm= CTX_wm_manager(C);
+
+ op->customdata= NULL;
+
+ /* we don't want to do undo pushes for operators that are being
+ called from operators that already do an undo push. usually
+ this will happen for python operators that call C operators */
+ if(wm->op_undo_depth == 0)
+ if(op->type->flag & OPTYPE_UNDO)
+ ED_undo_push_op(C, op);
+
+ if(repeat==0) {
+ if(G.f & G_DEBUG) {
+ char *buf = WM_operator_pystring(C, op->type, op->ptr, 1);
+ BKE_report(CTX_wm_reports(C), RPT_OPERATOR, buf);
+ MEM_freeN(buf);
+ }
+
+ if((wm->op_undo_depth == 0) && (op->type->flag & OPTYPE_REGISTER))
+ wm_operator_register(C, op);
+ else
+ WM_operator_free(op);
+ }
+}
+
/* if repeat is true, it doesn't register again, nor does it free */
static int wm_operator_exec(bContext *C, wmOperator *op, int repeat)
{
+ wmWindowManager *wm= CTX_wm_manager(C);
int retval= OPERATOR_CANCELLED;
if(op==NULL || op->type==NULL)
@@ -314,32 +342,22 @@ static int wm_operator_exec(bContext *C, wmOperator *op, int repeat)
if(0==WM_operator_poll(C, op->type))
return retval;
- if(op->type->exec)
+ if(op->type->exec) {
+ if(op->type->flag & OPTYPE_UNDO)
+ wm->op_undo_depth++;
+
retval= op->type->exec(C, op);
+
+ if(op->type->flag & OPTYPE_UNDO)
+ wm->op_undo_depth--;
+ }
if(retval & (OPERATOR_FINISHED|OPERATOR_CANCELLED))
if(op->reports->list.first)
uiPupMenuReports(C, op->reports);
- if(retval & OPERATOR_FINISHED) {
- op->customdata= NULL;
-
- if(op->type->flag & OPTYPE_UNDO)
- ED_undo_push_op(C, op);
-
- if(repeat==0) {
- if(G.f & G_DEBUG) {
- char *buf = WM_operator_pystring(C, op->type, op->ptr, 1);
- BKE_report(CTX_wm_reports(C), RPT_OPERATOR, buf);
- MEM_freeN(buf);
- }
-
- if((op->type->flag & OPTYPE_REGISTER))
- wm_operator_register(C, op);
- else
- WM_operator_free(op);
- }
- }
+ if(retval & OPERATOR_FINISHED)
+ wm_operator_finished(C, op, repeat);
else if(repeat==0)
WM_operator_free(op);
@@ -472,10 +490,24 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, P
if(op->type->invoke && event) {
wm_region_mouse_co(C, event);
+
+ if(op->type->flag & OPTYPE_UNDO)
+ wm->op_undo_depth++;
+
retval= op->type->invoke(C, op, event);
+
+ if(op->type->flag & OPTYPE_UNDO)
+ wm->op_undo_depth--;
}
- else if(op->type->exec)
+ else if(op->type->exec) {
+ if(op->type->flag & OPTYPE_UNDO)
+ wm->op_undo_depth++;
+
retval= op->type->exec(C, op);
+
+ if(op->type->flag & OPTYPE_UNDO)
+ wm->op_undo_depth--;
+ }
else
printf("invalid operator call %s\n", ot->idname); /* debug, important to leave a while, should never happen */
@@ -493,21 +525,7 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, P
if(retval & OPERATOR_HANDLED)
; /* do nothing, wm_operator_exec() has been called somewhere */
else if(retval & OPERATOR_FINISHED) {
- op->customdata= NULL;
-
- if(ot->flag & OPTYPE_UNDO)
- ED_undo_push_op(C, op);
-
- if(G.f & G_DEBUG) {
- char *buf = WM_operator_pystring(C, op->type, op->ptr, 1);
- BKE_report(CTX_wm_reports(C), RPT_OPERATOR, buf);
- MEM_freeN(buf);
- }
-
- if((ot->flag & OPTYPE_REGISTER))
- wm_operator_register(C, op);
- else
- WM_operator_free(op);
+ wm_operator_finished(C, op, 0);
}
else if(retval & OPERATOR_RUNNING_MODAL) {
/* grab cursor during blocking modal ops (X11)
@@ -657,8 +675,15 @@ int WM_operator_call_py(bContext *C, wmOperatorType *ot, int context, PointerRNA
wmWindowManager *wm= CTX_wm_manager(C);
op= wm_operator_create(wm, ot, properties, reports);
- if (op->type->exec)
+ if (op->type->exec) {
+ if(op->type->flag & OPTYPE_UNDO)
+ wm->op_undo_depth++;
+
retval= op->type->exec(C, op);
+
+ if(op->type->flag & OPTYPE_UNDO)
+ wm->op_undo_depth--;
+ }
else
printf("error \"%s\" operator has no exec function, python cannot call it\n", op->type->name);
#endif
@@ -721,6 +746,7 @@ static void wm_handler_op_context(bContext *C, wmEventHandler *handler)
void WM_event_remove_handlers(bContext *C, ListBase *handlers)
{
wmEventHandler *handler;
+ wmWindowManager *wm= CTX_wm_manager(C);
/* C is zero on freeing database, modal handlers then already were freed */
while((handler=handlers->first)) {
@@ -733,8 +759,14 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers)
wm_handler_op_context(C, handler);
+ if(handler->op->type->flag & OPTYPE_UNDO)
+ wm->op_undo_depth++;
+
handler->op->type->cancel(C, handler->op);
+ if(handler->op->type->flag & OPTYPE_UNDO)
+ wm->op_undo_depth--;
+
CTX_wm_area_set(C, area);
CTX_wm_region_set(C, region);
}
@@ -926,6 +958,7 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
if(ot->modal) {
/* we set context to where modal handler came from */
+ wmWindowManager *wm= CTX_wm_manager(C);
ScrArea *area= CTX_wm_area(C);
ARegion *region= CTX_wm_region(C);
@@ -933,8 +966,14 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
wm_region_mouse_co(C, event);
wm_event_modalkeymap(C, op, event);
+ if(ot->flag & OPTYPE_UNDO)
+ wm->op_undo_depth++;
+
retval= ot->modal(C, op, event);
+ if(ot->flag & OPTYPE_UNDO)
+ wm->op_undo_depth--;
+
/* putting back screen context, reval can pass trough after modal failures! */
if((retval & OPERATOR_PASS_THROUGH) || wm_event_always_pass(event)) {
CTX_wm_area_set(C, area);
@@ -956,21 +995,7 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
}
if(retval & OPERATOR_FINISHED) {
- op->customdata= NULL;
-
- if(ot->flag & OPTYPE_UNDO)
- ED_undo_push_op(C, op);
-
- if(G.f & G_DEBUG) {
- char *buf = WM_operator_pystring(C, op->type, op->ptr, 1);
- BKE_report(CTX_wm_reports(C), RPT_OPERATOR, buf);
- MEM_freeN(buf);
- }
-
- if((ot->flag & OPTYPE_REGISTER))
- wm_operator_register(C, op);
- else
- WM_operator_free(op);
+ wm_operator_finished(C, op, 0);
handler->op= NULL;
}
else if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
@@ -1053,6 +1078,7 @@ static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, wmEvent *eve
/* fileselect handlers are only in the window queue, so it's save to switch screens or area types */
static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event)
{
+ wmWindowManager *wm= CTX_wm_manager(C);
SpaceFile *sfile;
int action= WM_HANDLER_CONTINUE;
@@ -1119,7 +1145,15 @@ static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHa
uiPupMenuSaveOver(C, handler->op, (path)? path: "");
}
else {
- int retval= handler->op->type->exec(C, handler->op);
+ int retval;
+
+ if(handler->op->type->flag & OPTYPE_UNDO)
+ wm->op_undo_depth++;
+
+ retval= handler->op->type->exec(C, handler->op);
+
+ if(handler->op->type->flag & OPTYPE_UNDO)
+ wm->op_undo_depth--;
if (retval & OPERATOR_FINISHED)
if(G.f & G_DEBUG)
@@ -1144,9 +1178,16 @@ static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHa
}
}
else {
- if(handler->op->type->cancel)
+ if(handler->op->type->cancel) {
+ if(handler->op->type->flag & OPTYPE_UNDO)
+ wm->op_undo_depth++;
+
handler->op->type->cancel(C, handler->op);
+ if(handler->op->type->flag & OPTYPE_UNDO)
+ wm->op_undo_depth--;
+ }
+
WM_operator_free(handler->op);
}