fix for error in last commit - don't overwrite options in the new operator which...
[blender.git] / source / blender / windowmanager / intern / wm_event_system.c
index bed75f58e580c0239b6baebe6e40e5d3195267fa..079833f693ff3362a61fac85f13126ca4658fed9 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id$
- *
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
@@ -61,6 +59,7 @@
 
 #include "ED_fileselect.h"
 #include "ED_info.h"
+#include "ED_render.h"
 #include "ED_screen.h"
 #include "ED_view3d.h"
 #include "ED_util.h"
@@ -187,7 +186,7 @@ void wm_event_do_notifiers(bContext *C)
        wmWindowManager *wm= CTX_wm_manager(C);
        wmNotifier *note, *next;
        wmWindow *win;
-       unsigned int win_combine_v3d_datamask= 0;
+       uint64_t win_combine_v3d_datamask= 0;
        
        if(wm==NULL)
                return;
@@ -226,20 +225,8 @@ void wm_event_do_notifiers(bContext *C)
 
                        if(note->window==win || (note->window == NULL && (note->reference == NULL || note->reference == CTX_data_scene(C)))) {
                                if(note->category==NC_SCENE) {
-                                       if(note->data==ND_SCENEBROWSE) {
-                                               ED_screen_set_scene(C, note->reference);        // XXX hrms, think this over!
-                                               if(G.f & G_DEBUG)
-                                                       printf("scene set %p\n", note->reference);
-                                       }
-                                       else if(note->data==ND_FRAME)
+                                       if(note->data==ND_FRAME)
                                                do_anim= 1;
-                                       
-                                       if(note->action == NA_REMOVED) {
-                                               ED_screen_delete_scene(C, note->reference);     // XXX hrms, think this over!
-                                               if(G.f & G_DEBUG)
-                                                       printf("scene delete %p\n", note->reference);
-                                       }
-                                               
                                }
                        }
                        if(ELEM5(note->category, NC_SCENE, NC_OBJECT, NC_GEOM, NC_SCENE, NC_WM)) {
@@ -295,7 +282,7 @@ void wm_event_do_notifiers(bContext *C)
        
        /* combine datamasks so 1 win doesn't disable UV's in another [#26448] */
        for(win= wm->windows.first; win; win= win->next) {
-               win_combine_v3d_datamask |= ED_viewedit_datamask(win->screen);
+               win_combine_v3d_datamask |= ED_view3d_screen_datamask(win->screen);
        }
 
        /* cached: editor refresh callbacks now, they get context */
@@ -313,6 +300,7 @@ void wm_event_do_notifiers(bContext *C)
                /* XXX make lock in future, or separated derivedmesh users in scene */
                if(!G.rendering) {
                        /* depsgraph & animation: update tagged datablocks */
+                       Main *bmain = CTX_data_main(C);
 
                        /* copied to set's in scene_update_tagged_recursive() */
                        win->screen->scene->customdata_mask= win_combine_v3d_datamask;
@@ -320,7 +308,7 @@ void wm_event_do_notifiers(bContext *C)
                        /* XXX, hack so operators can enforce datamasks [#26482], gl render */
                        win->screen->scene->customdata_mask |= win->screen->scene->customdata_mask_modal;
 
-                       scene_update_tagged(CTX_data_main(C), win->screen->scene);
+                       scene_update_tagged(bmain, win->screen->scene);
                }
        }
 
@@ -453,13 +441,14 @@ void WM_event_print(wmEvent *event)
                RNA_enum_identifier(event_value_items, event->val, &val_id);
 
                printf("wmEvent - type:%d/%s, val:%d/%s, "
-                          "shift:%d, ctrl:%d, alt:%d, oskey:%d, keymodifier:%d, "
-                          "mouse:(%d,%d), ascii:'%c', utf8:'%.6s', "
-                          "keymap_idname:%s, pointer:%p\n",
-                          event->type, type_id, event->val, val_id,
-                          event->shift, event->ctrl, event->alt, event->oskey, event->keymodifier,
-                          event->x, event->y, event->ascii, event->utf8_buf,
-                          event->keymap_idname, (void *)event);
+                      "shift:%d, ctrl:%d, alt:%d, oskey:%d, keymodifier:%d, "
+                      "mouse:(%d,%d), ascii:'%c', utf8:'%.*s', "
+                      "keymap_idname:%s, pointer:%p\n",
+                      event->type, type_id, event->val, val_id,
+                      event->shift, event->ctrl, event->alt, event->oskey, event->keymodifier,
+                      event->x, event->y, event->ascii,
+                      BLI_str_utf8_size(event->utf8_buf), event->utf8_buf,
+                      event->keymap_idname, (void *)event);
        }
        else {
                printf("wmEvent - NULL\n");
@@ -596,12 +585,36 @@ static int wm_operator_exec(bContext *C, wmOperator *op, int repeat)
        
 }
 
-/* for running operators with frozen context (modal handlers, menus) */
+/* simply calls exec with basic checks */
+static int wm_operator_exec_notest(bContext *C, wmOperator *op)
+{
+       int retval= OPERATOR_CANCELLED;
+
+       if(op==NULL || op->type==NULL || op->type->exec==NULL)
+               return retval;
+
+       retval= op->type->exec(C, op);
+       OPERATOR_RETVAL_CHECK(retval);
+
+       return retval;
+}
+
+/* for running operators with frozen context (modal handlers, menus)
+ *
+ * warning: do not use this within an operator to call its self! [#29537] */
 int WM_operator_call(bContext *C, wmOperator *op)
 {
        return wm_operator_exec(C, op, 0);
 }
 
+/* this is intended to be used when an invoke operator wants to call exec on its self
+ * and is basically like running op->type->exec() directly, no poll checks no freeing,
+ * since we assume whoever called invokle will take care of that */
+int WM_operator_call_notest(bContext *C, wmOperator *op)
+{
+       return wm_operator_exec_notest(C, op);
+}
+
 /* do this operator again, put here so it can share above code */
 int WM_operator_repeat(bContext *C, wmOperator *op)
 {
@@ -631,7 +644,7 @@ static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot, P
        }
        else {
                IDPropertyTemplate val = {0};
-               op->properties= IDP_New(IDP_GROUP, val, "wmOperatorProperties");
+               op->properties= IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
        }
        RNA_pointer_create(&wm->id, ot->srna, op->properties, op->ptr);
 
@@ -716,6 +729,47 @@ static void wm_region_mouse_co(bContext *C, wmEvent *event)
        }
 }
 
+static int wm_operator_init_from_last(wmWindowManager *wm, wmOperator *op)
+{
+       int change= FALSE;
+       wmOperator *lastop;
+
+       for(lastop= wm->operators.last; lastop; lastop= lastop->prev) {
+               /* equality check is a bit paranoid but just incase */
+               if((op != lastop) && (op->type == (lastop->type))) {
+                       break;
+               }
+       }
+
+       if (lastop && op != lastop) {
+               PropertyRNA *iterprop;
+               iterprop= RNA_struct_iterator_property(op->type->srna);
+
+               RNA_PROP_BEGIN(op->ptr, itemptr, iterprop) {
+                       PropertyRNA *prop= itemptr.data;
+                       if((RNA_property_flag(prop) & PROP_SKIP_SAVE) == 0) {
+                               if (!RNA_property_is_set(op->ptr, prop)) { /* don't override a setting already set */
+                                       const char *identifier= RNA_property_identifier(prop);
+                                       IDProperty *idp_src= IDP_GetPropertyFromGroup(lastop->properties, identifier);
+                                       if(idp_src) {
+                                               IDProperty *idp_dst = IDP_CopyProperty(idp_src);
+
+                                               /* note - in the future this may need to be done recursively,
+                                                * but for now RNA doesn't access nested operators */
+                                               idp_dst->flag |= IDP_FLAG_GHOST;
+
+                                               IDP_ReplaceInGroup(op->properties, idp_dst);
+                                               change= TRUE;
+                                       }
+                               }
+                       }
+               }
+               RNA_PROP_END;
+       }
+
+       return change;
+}
+
 static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, PointerRNA *properties, ReportList *reports, short poll_only)
 {
        wmWindowManager *wm= CTX_wm_manager(C);
@@ -728,6 +782,11 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, P
        if(WM_operator_poll(C, ot)) {
                wmOperator *op= wm_operator_create(wm, ot, properties, reports); /* if reports==NULL, theyll be initialized */
                
+               /* initialize setting from previous run */
+               if(wm->op_undo_depth == 0 && (ot->flag & OPTYPE_REGISTER)) { /* not called by py script */
+                       wm_operator_init_from_last(wm, op);
+               }
+
                if((G.f & G_DEBUG) && event && event->type!=MOUSEMOVE)
                        printf("handle evt %d win %d op %s\n", event?event->type:0, CTX_wm_screen(C)->subwinactive, ot->idname); 
                
@@ -1954,8 +2013,9 @@ void wm_event_do_handlers(bContext *C)
                                        win->eventstate->prevy= event->y;
                                        //printf("win->eventstate->prev = %d %d\n", event->x, event->y);
                                }
-                               else
-                                       ;//printf("not setting prev to %d %d\n", event->x, event->y);
+                               else {
+                                       //printf("not setting prev to %d %d\n", event->x, event->y);
+                               }
                        }
                        
                        /* store last event for this window */
@@ -2611,39 +2671,52 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
                        GHOST_TEventKeyData *kd= customdata;
                        event.type= convert_key(kd->key);
                        event.ascii= kd->ascii;
-                       strcpy(event.utf8_buf, kd->utf8_buf);
+                       memcpy(event.utf8_buf, kd->utf8_buf,sizeof(event.utf8_buf));/* might be not null terminated*/
                        event.val= (type==GHOST_kEventKeyDown)?KM_PRESS:KM_RELEASE;
                        
                        /* exclude arrow keys, esc, etc from text input */
-                       if(type==GHOST_kEventKeyUp || (event.ascii<32 && event.ascii>0))
+                       if(type==GHOST_kEventKeyUp) {
                                event.ascii= '\0';
-                       
-                       /* modifiers */
-                       if (event.type==LEFTSHIFTKEY || event.type==RIGHTSHIFTKEY) {
-                               event.shift= evt->shift= (event.val==KM_PRESS);
-                               if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->oskey))
-                                  event.shift= evt->shift = 3;         // define?
-                       } 
-                       else if (event.type==LEFTCTRLKEY || event.type==RIGHTCTRLKEY) {
-                               event.ctrl= evt->ctrl= (event.val==KM_PRESS);
-                               if(event.val==KM_PRESS && (evt->shift || evt->alt || evt->oskey))
-                                  event.ctrl= evt->ctrl = 3;           // define?
-                       } 
-                       else if (event.type==LEFTALTKEY || event.type==RIGHTALTKEY) {
-                               event.alt= evt->alt= (event.val==KM_PRESS);
-                               if(event.val==KM_PRESS && (evt->ctrl || evt->shift || evt->oskey))
-                                  event.alt= evt->alt = 3;             // define?
-                       } 
-                       else if (event.type==OSKEY) {
-                               event.oskey= evt->oskey= (event.val==KM_PRESS);
-                               if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->shift))
-                                  event.oskey= evt->oskey = 3;         // define?
+
+                               /* ghost should do this already for key up */
+                               if (event.utf8_buf[0]) {
+                                       printf("%s: ghost on your platform is misbehaving, utf8 events on key up!\n", __func__);
+                               }
+                               event.utf8_buf[0]= '\0';
                        }
-                       else {
+                       else if (event.ascii<32 && event.ascii > 0) {
+                               event.ascii= '\0';
+                               /* TODO. should this also zero utf8?, dont for now, campbell */
+                       }
+
+                       if (event.utf8_buf[0]) {
+                               if (BLI_str_utf8_size(event.utf8_buf) == -1) {
+                                       printf("%s: ghost detected an invalid unicode character '%d'!\n", __func__, (int)(unsigned char)event.utf8_buf[0]);
+                                       event.utf8_buf[0]= '\0';
+                               }
+                       }
+
+                       /* modifiers */
+                       /* assigning both first and second is strange - campbell */
+                       switch(event.type) {
+                       case LEFTSHIFTKEY: case RIGHTSHIFTKEY:
+                               event.shift= evt->shift= (event.val==KM_PRESS) ? ((evt->ctrl || evt->alt || evt->oskey) ? (KM_MOD_FIRST | KM_MOD_SECOND) : KM_MOD_FIRST) : FALSE;
+                               break;
+                       case LEFTCTRLKEY: case RIGHTCTRLKEY:
+                               event.ctrl= evt->ctrl= (event.val==KM_PRESS) ? ((evt->shift || evt->alt || evt->oskey) ? (KM_MOD_FIRST | KM_MOD_SECOND) : KM_MOD_FIRST) : FALSE;
+                               break;
+                       case LEFTALTKEY: case RIGHTALTKEY:
+                               event.alt= evt->alt= (event.val==KM_PRESS) ? ((evt->ctrl || evt->shift || evt->oskey) ? (KM_MOD_FIRST | KM_MOD_SECOND) : KM_MOD_FIRST) : FALSE;
+                               break;
+                       case OSKEY:
+                               event.oskey= evt->oskey= (event.val==KM_PRESS) ? ((evt->ctrl || evt->alt || evt->shift) ? (KM_MOD_FIRST | KM_MOD_SECOND) : KM_MOD_FIRST) : FALSE;
+                               break;
+                       default:
                                if(event.val==KM_PRESS && event.keymodifier==0)
                                        evt->keymodifier= event.type; /* only set in eventstate, for next event */
                                else if(event.val==KM_RELEASE && event.keymodifier==event.type)
                                        event.keymodifier= evt->keymodifier= 0;
+                               break;
                        }
 
                        /* this case happens on some systems that on holding a key pressed,
@@ -2652,6 +2725,11 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
                           key we don't want the key modifier */
                        if(event.keymodifier == event.type)
                                event.keymodifier= 0;
+                       /* this case happened with an external numpad, it's not really clear
+                          why, but it's also impossible to map a key modifier to an unknwon
+                          key, so it shouldn't harm */
+                       if(event.keymodifier == UNKNOWNKEY)
+                               event.keymodifier= 0;
                        
                        /* if test_break set, it catches this. XXX Keep global for now? */
                        if(event.type==ESCKEY)