Cleanup: use `rna_enum_` prefix for RNA enums
[blender.git] / source / blender / editors / space_node / node_edit.c
index 37b7b1cfd5fe25916d4eb688fafa2236fc34fca8..e4861a713b7b954e0c6247f7c44a2a64270ae8b1 100644 (file)
 
 #include "MEM_guardedalloc.h"
 
-#include "DNA_action_types.h"
-#include "DNA_anim_types.h"
 #include "DNA_lamp_types.h"
 #include "DNA_material_types.h"
 #include "DNA_node_types.h"
-#include "DNA_object_types.h"
 #include "DNA_text_types.h"
 #include "DNA_world_types.h"
 
 #include "BLI_math.h"
 #include "BLI_blenlib.h"
 
-#include "BKE_blender.h"
 #include "BKE_context.h"
 #include "BKE_depsgraph.h"
 #include "BKE_global.h"
 #include "BKE_image.h"
 #include "BKE_library.h"
 #include "BKE_main.h"
-#include "BKE_material.h"
 #include "BKE_node.h"
-#include "BKE_paint.h"
 #include "BKE_report.h"
 #include "BKE_scene.h"
-#include "BKE_texture.h"
 
 #include "RE_engine.h"
 #include "RE_pipeline.h"
@@ -79,8 +72,6 @@
 #include "IMB_imbuf_types.h"
 
 #include "node_intern.h"  /* own include */
-#include "NOD_common.h"
-#include "NOD_socket.h"
 #include "NOD_composite.h"
 #include "NOD_shader.h"
 #include "NOD_texture.h"
 
 /* ***************** composite job manager ********************** */
 
+enum {
+       COM_RECALC_COMPOSITE = 1,
+       COM_RECALC_VIEWER    = 2
+};
+
 typedef struct CompoJob {
        Scene *scene;
        bNodeTree *ntree;
        bNodeTree *localtree;
-       short *stop;
+       const short *stop;
        short *do_update;
        float *progress;
-       short need_sync;
+       int recalc_flags;
 } CompoJob;
 
+static void compo_tag_output_nodes(bNodeTree *nodetree, int recalc_flags)
+{
+       bNode *node;
+
+       for (node = nodetree->nodes.first; node; node = node->next) {
+               if (node->type == CMP_NODE_COMPOSITE) {
+                       if (recalc_flags & COM_RECALC_COMPOSITE)
+                               node->flag |= NODE_DO_OUTPUT_RECALC;
+               }
+               else if (node->type == CMP_NODE_VIEWER || node->type == CMP_NODE_SPLITVIEWER) {
+                       if (recalc_flags & COM_RECALC_VIEWER)
+                               node->flag |= NODE_DO_OUTPUT_RECALC;
+               }
+               else if (node->type == NODE_GROUP) {
+                       if (node->id)
+                               compo_tag_output_nodes((bNodeTree *)node->id, recalc_flags);
+               }
+       }
+}
+
+static int compo_get_recalc_flags(const bContext *C)
+{
+       wmWindowManager *wm = CTX_wm_manager(C);
+       wmWindow *win;
+       int recalc_flags = 0;
+
+       for (win = wm->windows.first; win; win = win->next) {
+               bScreen *sc = win->screen;
+               ScrArea *sa;
+
+               for (sa = sc->areabase.first; sa; sa = sa->next) {
+                       if (sa->spacetype == SPACE_IMAGE) {
+                               SpaceImage *sima = sa->spacedata.first;
+                               if (sima->image) {
+                                       if (sima->image->type == IMA_TYPE_R_RESULT)
+                                               recalc_flags |= COM_RECALC_COMPOSITE;
+                                       else if (sima->image->type == IMA_TYPE_COMPOSITE)
+                                               recalc_flags |= COM_RECALC_VIEWER;
+                               }
+                       }
+                       else if (sa->spacetype == SPACE_NODE) {
+                               SpaceNode *snode = sa->spacedata.first;
+                               if (snode->flag & SNODE_BACKDRAW)
+                                       recalc_flags |= COM_RECALC_VIEWER;
+                       }
+               }
+       }
+
+       return recalc_flags;
+}
+
 /* called by compo, only to check job 'stop' value */
 static int compo_breakjob(void *cjv)
 {
@@ -114,13 +161,12 @@ static int compo_breakjob(void *cjv)
                );
 }
 
-/* called by compo, wmJob sends notifier, old compositor system only */
-static void compo_statsdrawjob(void *cjv, char *UNUSED(str))
+/* called by compo, wmJob sends notifier */
+static void compo_statsdrawjob(void *cjv, const char *UNUSED(str))
 {
        CompoJob *cj = cjv;
        
-       *(cj->do_update) = TRUE;
-       cj->need_sync = TRUE;
+       *(cj->do_update) = true;
 }
 
 /* called by compo, wmJob sends notifier */
@@ -128,7 +174,7 @@ static void compo_redrawjob(void *cjv)
 {
        CompoJob *cj = cjv;
        
-       *(cj->do_update) = TRUE;
+       *(cj->do_update) = true;
 }
 
 static void compo_freejob(void *cjv)
@@ -148,21 +194,15 @@ static void compo_initjob(void *cjv)
        CompoJob *cj = cjv;
 
        cj->localtree = ntreeLocalize(cj->ntree);
+
+       if (cj->recalc_flags)
+               compo_tag_output_nodes(cj->localtree, cj->recalc_flags);
 }
 
 /* called before redraw notifiers, it moves finished previews over */
-static void compo_updatejob(void *cjv)
+static void compo_updatejob(void *UNUSED(cjv))
 {
-       CompoJob *cj = cjv;
-
-       if (cj->need_sync) {
-               /* was used by old compositor system only */
-               ntreeLocalSync(cj->localtree, cj->ntree);
-
-               cj->need_sync = FALSE;
-       }
-
-       WM_main_add_notifier(NC_WINDOW | ND_DRAW, NULL);
+       WM_main_add_notifier(NC_SCENE | ND_COMPO_RESULT, NULL);
 }
 
 static void compo_progressjob(void *cjv, float progress)
@@ -172,15 +212,15 @@ static void compo_progressjob(void *cjv, float progress)
        *(cj->progress) = progress;
 }
 
-
 /* only this runs inside thread */
 static void compo_startjob(void *cjv, short *stop, short *do_update, float *progress)
 {
        CompoJob *cj = cjv;
        bNodeTree *ntree = cj->localtree;
        Scene *scene = cj->scene;
+       SceneRenderView *srv;
 
-       if (scene->use_nodes == FALSE)
+       if (scene->use_nodes == false)
                return;
        
        cj->stop = stop;
@@ -197,8 +237,17 @@ static void compo_startjob(void *cjv, short *stop, short *do_update, float *prog
        ntree->udh = cj;
 
        // XXX BIF_store_spare();
-       
-       ntreeCompositExecTree(ntree, &cj->scene->r, 0, 1, &scene->view_settings, &scene->display_settings);  /* 1 is do_previews */
+       /* 1 is do_previews */
+
+       if ((cj->scene->r.scemode & R_MULTIVIEW) == 0) {
+               ntreeCompositExecTree(cj->scene, ntree, &cj->scene->r, false, true, &scene->view_settings, &scene->display_settings, "");
+       }
+       else {
+               for (srv = scene->r.views.first; srv; srv = srv->next) {
+                       if (BKE_scene_multiview_is_render_view_active(&scene->r, srv) == false) continue;
+                       ntreeCompositExecTree(cj->scene, ntree, &cj->scene->r, false, true, &scene->view_settings, &scene->display_settings, srv->name);
+               }
+       }
 
        ntree->test_break = NULL;
        ntree->stats_draw = NULL;
@@ -217,6 +266,7 @@ void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene
 {
        wmJob *wm_job;
        CompoJob *cj;
+       Scene *scene = CTX_data_scene(C);
 
        /* to fix bug: [#32272] */
        if (G.is_rendering) {
@@ -224,20 +274,23 @@ void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene
        }
 
 #ifdef USE_ESC_COMPO
-       G.is_break = FALSE;
+       G.is_break = false;
 #endif
 
+       BKE_image_backup_render(scene, BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result"));
+
        wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene_owner, "Compositing",
                             WM_JOB_EXCL_RENDER | WM_JOB_PROGRESS, WM_JOB_TYPE_COMPOSITE);
        cj = MEM_callocN(sizeof(CompoJob), "compo job");
 
        /* customdata for preview thread */
-       cj->scene = CTX_data_scene(C);
+       cj->scene = scene;
        cj->ntree = nodetree;
+       cj->recalc_flags = compo_get_recalc_flags(C);
 
        /* setup job */
        WM_jobs_customdata_set(wm_job, cj, compo_freejob);
-       WM_jobs_timer(wm_job, 0.1, NC_SCENE, NC_SCENE | ND_COMPO_RESULT);
+       WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_COMPO_RESULT, NC_SCENE | ND_COMPO_RESULT);
        WM_jobs_callbacks(wm_job, compo_startjob, compo_initjob, compo_updatejob, NULL);
 
        WM_jobs_start(CTX_wm_manager(C), wm_job);
@@ -256,18 +309,14 @@ int composite_node_active(bContext *C)
        return 0;
 }
 
-static int has_nodetree(bNodeTree *ntree, bNodeTree *lookup)
+/* operator poll callback */
+int composite_node_editable(bContext *C)
 {
-       bNode *node;
-       
-       if (ntree == lookup)
-               return 1;
-       
-       for (node = ntree->nodes.first; node; node = node->next)
-               if (node->type == NODE_GROUP && node->id)
-                       if (has_nodetree((bNodeTree *)node->id, lookup))
-                               return 1;
-       
+       if (ED_operator_node_editable(C)) {
+               SpaceNode *snode = CTX_wm_space_node(C);
+               if (ED_node_is_compositor(snode))
+                       return 1;
+       }
        return 0;
 }
 
@@ -278,7 +327,7 @@ void snode_dag_update(bContext *C, SpaceNode *snode)
        /* for groups, update all ID's using this */
        if (snode->edittree != snode->nodetree) {
                FOREACH_NODETREE(bmain, tntree, id) {
-                       if (has_nodetree(tntree, snode->edittree))
+                       if (ntreeHasTree(tntree, snode->edittree))
                                DAG_id_tag_update(id, 0);
                } FOREACH_NODETREE_END
        }
@@ -288,14 +337,22 @@ void snode_dag_update(bContext *C, SpaceNode *snode)
 
 void snode_notify(bContext *C, SpaceNode *snode)
 {
+       ID *id = snode->id;
+
        WM_event_add_notifier(C, NC_NODE | NA_EDITED, NULL);
 
-       if (ED_node_is_shader(snode))
-               WM_event_add_notifier(C, NC_MATERIAL | ND_NODES, snode->id);
+       if (ED_node_is_shader(snode)) {
+               if (GS(id->name) == ID_MA)
+                       WM_main_add_notifier(NC_MATERIAL | ND_SHADING, id);
+               else if (GS(id->name) == ID_LA)
+                       WM_main_add_notifier(NC_LAMP | ND_LIGHTING, id);
+               else if (GS(id->name) == ID_WO)
+                       WM_main_add_notifier(NC_WORLD | ND_WORLD, id);
+       }
        else if (ED_node_is_compositor(snode))
-               WM_event_add_notifier(C, NC_SCENE | ND_NODES, snode->id);
+               WM_event_add_notifier(C, NC_SCENE | ND_NODES, id);
        else if (ED_node_is_texture(snode))
-               WM_event_add_notifier(C, NC_TEXTURE | ND_NODES, snode->id);
+               WM_event_add_notifier(C, NC_TEXTURE | ND_NODES, id);
 }
 
 void ED_node_set_tree_type(SpaceNode *snode, bNodeTreeType *typeinfo)
@@ -306,17 +363,17 @@ void ED_node_set_tree_type(SpaceNode *snode, bNodeTreeType *typeinfo)
                snode->tree_idname[0] = '\0';
 }
 
-int ED_node_is_compositor(struct SpaceNode *snode)
+bool ED_node_is_compositor(struct SpaceNode *snode)
 {
        return STREQ(snode->tree_idname, ntreeType_Composite->idname);
 }
 
-int ED_node_is_shader(struct SpaceNode *snode)
+bool ED_node_is_shader(struct SpaceNode *snode)
 {
        return STREQ(snode->tree_idname, ntreeType_Shader->idname);
 }
 
-int ED_node_is_texture(struct SpaceNode *snode)
+bool ED_node_is_texture(struct SpaceNode *snode)
 {
        return STREQ(snode->tree_idname, ntreeType_Texture->idname);
 }
@@ -329,15 +386,11 @@ void ED_node_shader_default(const bContext *C, ID *id)
        bNode *in, *out;
        bNodeSocket *fromsock, *tosock, *sock;
        bNodeTree *ntree;
-       PointerRNA ptr;
        int output_type, shader_type;
        float color[4] = { 0.0f, 0.0f, 0.0f, 1.0f }, strength = 1.0f;
        
        ntree = ntreeAddTree(NULL, "Shader Nodetree", ntreeType_Shader->idname);
 
-       RNA_id_pointer_create((ID *)ntree, &ptr);
-       RNA_boolean_set(&ptr, "is_local_tree", TRUE);
-
        switch (GS(id->name)) {
                case ID_MA:
                {
@@ -416,7 +469,7 @@ void ED_node_shader_default(const bContext *C, ID *id)
                }
        }
        
-       ntreeUpdateTree(ntree);
+       ntreeUpdateTree(CTX_data_main(C), ntree);
 }
 
 /* assumes nothing being done in ntree yet, sets the default in/out node */
@@ -425,7 +478,6 @@ void ED_node_composit_default(const bContext *C, struct Scene *sce)
 {
        bNode *in, *out;
        bNodeSocket *fromsock, *tosock;
-       PointerRNA ptr;
        
        /* but lets check it anyway */
        if (sce->nodetree) {
@@ -436,22 +488,15 @@ void ED_node_composit_default(const bContext *C, struct Scene *sce)
        
        sce->nodetree = ntreeAddTree(NULL, "Compositing Nodetree", ntreeType_Composite->idname);
        
-       RNA_id_pointer_create((ID *)sce->nodetree, &ptr);
-       RNA_boolean_set(&ptr, "is_local_tree", TRUE);
-       
        sce->nodetree->chunksize = 256;
        sce->nodetree->edit_quality = NTREE_QUALITY_HIGH;
        sce->nodetree->render_quality = NTREE_QUALITY_HIGH;
        
        out = nodeAddStaticNode(C, sce->nodetree, CMP_NODE_COMPOSITE);
        out->locx = 300.0f; out->locy = 400.0f;
-       out->id = &sce->id;
-       id_us_plus(out->id);
        
        in = nodeAddStaticNode(C, sce->nodetree, CMP_NODE_R_LAYERS);
        in->locx = 10.0f; in->locy = 400.0f;
-       in->id = &sce->id;
-       id_us_plus(in->id);
        nodeSetActive(sce->nodetree, in);
        
        /* links from color to color */
@@ -459,7 +504,7 @@ void ED_node_composit_default(const bContext *C, struct Scene *sce)
        tosock = out->inputs.first;
        nodeAddLink(sce->nodetree, in, fromsock, out, tosock);
        
-       ntreeUpdateTree(sce->nodetree);
+       ntreeUpdateTree(CTX_data_main(C), sce->nodetree);
        
        // XXX ntreeCompositForceHidden(sce->nodetree);
 }
@@ -470,7 +515,6 @@ void ED_node_texture_default(const bContext *C, Tex *tx)
 {
        bNode *in, *out;
        bNodeSocket *fromsock, *tosock;
-       PointerRNA ptr;
        
        /* but lets check it anyway */
        if (tx->nodetree) {
@@ -481,9 +525,6 @@ void ED_node_texture_default(const bContext *C, Tex *tx)
        
        tx->nodetree = ntreeAddTree(NULL, "Texture Nodetree", ntreeType_Texture->idname);
        
-       RNA_id_pointer_create((ID *)tx->nodetree, &ptr);
-       RNA_boolean_set(&ptr, "is_local_tree", TRUE);
-       
        out = nodeAddStaticNode(C, tx->nodetree, TEX_NODE_OUTPUT);
        out->locx = 300.0f; out->locy = 300.0f;
        
@@ -495,7 +536,7 @@ void ED_node_texture_default(const bContext *C, Tex *tx)
        tosock = out->inputs.first;
        nodeAddLink(tx->nodetree, in, fromsock, out, tosock);
        
-       ntreeUpdateTree(tx->nodetree);
+       ntreeUpdateTree(CTX_data_main(C), tx->nodetree);
 }
 
 /* Here we set the active tree(s), even called for each redraw now, so keep it fast :) */
@@ -516,13 +557,14 @@ void snode_set_context(const bContext *C)
        if (!treetype ||
            (treetype->poll && !treetype->poll(C, treetype)))
        {
-               /* invalid tree type, disable */
-               snode->tree_idname[0] = '\0';
-               ED_node_tree_start(snode, NULL, NULL, NULL);
+               /* invalid tree type, skip
+                * NB: not resetting the node path here, invalid bNodeTreeType
+                * may still be registered at a later point.
+                */
                return;
        }
        
-       if (snode->nodetree && strcmp(snode->nodetree->idname, snode->tree_idname) != 0) {
+       if (snode->nodetree && !STREQ(snode->nodetree->idname, snode->tree_idname)) {
                /* current tree does not match selected type, clear tree path */
                ntree = NULL;
                id = NULL;
@@ -543,6 +585,14 @@ void snode_set_context(const bContext *C)
        if (snode->nodetree != ntree || snode->id != id || snode->from != from) {
                ED_node_tree_start(snode, ntree, id, from);
        }
+       
+       /* XXX Legacy hack to update render layer node outputs.
+        * This should be handled by the depsgraph eventually ...
+        */
+       if (ED_node_is_compositor(snode) && snode->nodetree) {
+               /* update output sockets based on available layers */
+               ntreeCompositForceHidden(snode->nodetree);
+       }
 }
 
 void snode_update(SpaceNode *snode, bNode *node)
@@ -570,13 +620,13 @@ void snode_update(SpaceNode *snode, bNode *node)
 
 void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
 {
-       int was_active_texture = (node->flag & NODE_ACTIVE_TEXTURE);
+       const bool was_active_texture = (node->flag & NODE_ACTIVE_TEXTURE) != 0;
 
        nodeSetActive(ntree, node);
        
        if (node->type != NODE_GROUP) {
-               int was_output = (node->flag & NODE_DO_OUTPUT);
-               int do_update = 0;
+               const bool was_output = (node->flag & NODE_DO_OUTPUT) != 0;
+               bool do_update = false;
                
                /* generic node group output: set node as active output */
                if (node->type == NODE_GROUP_OUTPUT) {
@@ -593,14 +643,16 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
                /* tree specific activate calls */
                if (ntree->type == NTREE_SHADER) {
                        /* when we select a material, active texture is cleared, for buttons */
-                       if (node->id && ELEM3(GS(node->id->name), ID_MA, ID_LA, ID_WO))
+                       if (node->id && ELEM(GS(node->id->name), ID_MA, ID_LA, ID_WO))
                                nodeClearActiveID(ntree, ID_TE);
                        
-                       if (node->type == SH_NODE_OUTPUT) {
+                       if (ELEM(node->type, SH_NODE_OUTPUT, SH_NODE_OUTPUT_MATERIAL,
+                                SH_NODE_OUTPUT_WORLD, SH_NODE_OUTPUT_LAMP, SH_NODE_OUTPUT_LINESTYLE))
+                       {
                                bNode *tnode;
                                
                                for (tnode = ntree->nodes.first; tnode; tnode = tnode->next)
-                                       if (tnode->type == SH_NODE_OUTPUT)
+                                       if (tnode->type == node->type)
                                                tnode->flag &= ~NODE_DO_OUTPUT;
                                
                                node->flag |= NODE_DO_OUTPUT;
@@ -613,11 +665,16 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
                        /* if active texture changed, free glsl materials */
                        if ((node->flag & NODE_ACTIVE_TEXTURE) && !was_active_texture) {
                                Material *ma;
+                               World *wo;
 
                                for (ma = bmain->mat.first; ma; ma = ma->id.next)
-                                       if (ma->nodetree && ma->use_nodes && has_nodetree(ma->nodetree, ntree))
-                                               GPU_material_free(ma);
+                                       if (ma->nodetree && ma->use_nodes && ntreeHasTree(ma->nodetree, ntree))
+                                               GPU_material_free(&ma->gpumaterial);
 
+                               for (wo = bmain->world.first; wo; wo = wo->id.next)
+                                       if (wo->nodetree && wo->use_nodes && ntreeHasTree(wo->nodetree, ntree))
+                                               GPU_material_free(&wo->gpumaterial);
+                               
                                WM_main_add_notifier(NC_IMAGE, NULL);
                        }
 
@@ -644,9 +701,14 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
                                Scene *scene;
 
                                for (scene = bmain->scene.first; scene; scene = scene->id.next) {
-                                       if (scene->nodetree && scene->use_nodes && has_nodetree(scene->nodetree, ntree)) {
+                                       if (scene->nodetree && scene->use_nodes && ntreeHasTree(scene->nodetree, ntree)) {
                                                if (node->id == NULL || node->id == (ID *)scene) {
+                                                       int num_layers = BLI_listbase_count(&scene->r.layers);
                                                        scene->r.actlay = node->custom1;
+                                                       /* Clamp the value, because it might have come from a different
+                                                        * scene which could have more render layers than new one.
+                                                        */
+                                                       scene->r.actlay = min_ff(scene->r.actlay, num_layers - 1);
                                                }
                                        }
                                }
@@ -678,6 +740,34 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
        }
 }
 
+void ED_node_id_unref(SpaceNode *snode, const ID *id)
+{
+       if (GS(id->name) == ID_SCE) {
+               if (snode->id == id) {
+                       /* nasty DNA logic for SpaceNode:
+                        * ideally should be handled by editor code, but would be bad level call
+                        */
+                       bNodeTreePath *path, *path_next;
+                       for (path = snode->treepath.first; path; path = path_next) {
+                               path_next = path->next;
+                               MEM_freeN(path);
+                       }
+                       BLI_listbase_clear(&snode->treepath);
+
+                       snode->id = NULL;
+                       snode->from = NULL;
+                       snode->nodetree = NULL;
+                       snode->edittree = NULL;
+               }
+       }
+       else if (GS(id->name) == ID_OB) {
+               if (snode->from == id) {
+                       snode->flag &= ~SNODE_PIN;
+                       snode->from = NULL;
+               }
+       }
+}
+
 void ED_node_post_apply_transform(bContext *UNUSED(C), bNodeTree *UNUSED(ntree))
 {
        /* XXX This does not work due to layout functions relying on node->block,
@@ -699,9 +789,9 @@ static int edit_node_poll(bContext *C)
 static void edit_node_properties(wmOperatorType *ot)
 {
        /* XXX could node be a context pointer? */
-       RNA_def_string(ot->srna, "node", "", MAX_NAME, "Node", "");
+       RNA_def_string(ot->srna, "node", NULL, MAX_NAME, "Node", "");
        RNA_def_int(ot->srna, "socket", 0, 0, MAX_SOCKET, "Socket", "", 0, MAX_SOCKET);
-       RNA_def_enum(ot->srna, "in_out", node_socket_in_out_items, SOCK_IN, "Socket Side", "");
+       RNA_def_enum(ot->srna, "in_out", rna_enum_node_socket_in_out_items, SOCK_IN, "Socket Side", "");
 }
 
 static int edit_node_invoke_properties(bContext *C, wmOperator *op)
@@ -796,14 +886,14 @@ static void node_resize_init(bContext *C, wmOperator *op, const wmEvent *UNUSED(
        nsw->oldminiwidth = node->miniwidth;
        nsw->directions = dir;
        
-       WM_cursor_modal(CTX_wm_window(C), node_get_resize_cursor(dir));
+       WM_cursor_modal_set(CTX_wm_window(C), node_get_resize_cursor(dir));
        /* add modal handler */
        WM_event_add_modal_handler(C, op);
 }
 
-static void node_resize_exit(bContext *C, wmOperator *op, int UNUSED(cancel))
+static void node_resize_exit(bContext *C, wmOperator *op, bool UNUSED(cancel))
 {
-       WM_cursor_restore(CTX_wm_window(C));
+       WM_cursor_modal_restore(CTX_wm_window(C));
        
        MEM_freeN(op->customdata);
        op->customdata = NULL;
@@ -825,37 +915,38 @@ static int node_resize_modal(bContext *C, wmOperator *op, const wmEvent *event)
                        dy = (my - nsw->mystart) / UI_DPI_FAC;
                        
                        if (node) {
-                               if (node->flag & NODE_HIDDEN) {
-                                       float widthmin = 0.0f;
-                                       float widthmax = 100.0f;
-                                       if (nsw->directions & NODE_RESIZE_RIGHT) {
-                                               node->miniwidth = nsw->oldminiwidth + dx;
-                                               CLAMP(node->miniwidth, widthmin, widthmax);
-                                       }
-                                       if (nsw->directions & NODE_RESIZE_LEFT) {
-                                               float locmax = nsw->oldlocx + nsw->oldminiwidth;
-                                               
-                                               node->locx = nsw->oldlocx + dx;
-                                               CLAMP(node->locx, locmax - widthmax, locmax - widthmin);
-                                               node->miniwidth = locmax - node->locx;
-                                       }
+                               /* width can use node->width or node->miniwidth (hidden nodes) */
+                               float *pwidth;
+                               float oldwidth, widthmin, widthmax;
+                               /* ignore hidden flag for frame nodes */
+                               bool use_hidden = (node->type != NODE_FRAME);
+                               if (use_hidden && node->flag & NODE_HIDDEN) {
+                                       pwidth = &node->miniwidth;
+                                       oldwidth = nsw->oldminiwidth;
+                                       widthmin = 0.0f;
+                                       widthmax = 100.0f;
                                }
                                else {
-                                       float widthmin = node->typeinfo->minwidth;
-                                       float widthmax = node->typeinfo->maxwidth;
+                                       pwidth = &node->width;
+                                       oldwidth = nsw->oldwidth;
+                                       widthmin = node->typeinfo->minwidth;
+                                       widthmax = node->typeinfo->maxwidth;
+                               }
+                               
+                               {
                                        if (nsw->directions & NODE_RESIZE_RIGHT) {
-                                               node->width = nsw->oldwidth + dx;
-                                               CLAMP(node->width, widthmin, widthmax);
+                                               *pwidth = oldwidth + dx;
+                                               CLAMP(*pwidth, widthmin, widthmax);
                                        }
                                        if (nsw->directions & NODE_RESIZE_LEFT) {
-                                               float locmax = nsw->oldlocx + nsw->oldwidth;
+                                               float locmax = nsw->oldlocx + oldwidth;
                                                
                                                node->locx = nsw->oldlocx + dx;
                                                CLAMP(node->locx, locmax - widthmax, locmax - widthmin);
-                                               node->width = locmax - node->locx;
+                                               *pwidth = locmax - node->locx;
                                        }
                                }
-                       
+                               
                                /* height works the other way round ... */
                                {
                                        float heightmin = UI_DPI_FAC * node->typeinfo->minheight;
@@ -903,7 +994,7 @@ static int node_resize_modal(bContext *C, wmOperator *op, const wmEvent *event)
                case MIDDLEMOUSE:
                case RIGHTMOUSE:
                        
-                       node_resize_exit(C, op, 0);
+                       node_resize_exit(C, op, false);
                        ED_node_post_apply_transform(C, snode->edittree);
                        
                        return OPERATOR_FINISHED;
@@ -932,11 +1023,9 @@ static int node_resize_invoke(bContext *C, wmOperator *op, const wmEvent *event)
        return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
 }
 
-static int node_resize_cancel(bContext *C, wmOperator *op)
+static void node_resize_cancel(bContext *C, wmOperator *op)
 {
-       node_resize_exit(C, op, 1);
-
-       return OPERATOR_CANCELLED;
+       node_resize_exit(C, op, true);
 }
 
 void NODE_OT_resize(wmOperatorType *ot)
@@ -998,7 +1087,7 @@ void node_set_hidden_sockets(SpaceNode *snode, bNode *node, int set)
 
 /* checks snode->mouse position, and returns found node/socket */
 /* type is SOCK_IN and/or SOCK_OUT */
-int node_find_indicated_socket(SpaceNode *snode, bNode **nodep, bNodeSocket **sockp, int in_out)
+int node_find_indicated_socket(SpaceNode *snode, bNode **nodep, bNodeSocket **sockp, float cursor[2], int in_out)
 {
        bNode *node;
        bNodeSocket *sock;
@@ -1010,10 +1099,10 @@ int node_find_indicated_socket(SpaceNode *snode, bNode **nodep, bNodeSocket **so
        /* check if we click in a socket */
        for (node = snode->edittree->nodes.first; node; node = node->next) {
                
-               rect.xmin = snode->cursor[0] - (NODE_SOCKSIZE + 4);
-               rect.ymin = snode->cursor[1] - (NODE_SOCKSIZE + 4);
-               rect.xmax = snode->cursor[0] + (NODE_SOCKSIZE + 4);
-               rect.ymax = snode->cursor[1] + (NODE_SOCKSIZE + 4);
+               rect.xmin = cursor[0] - (NODE_SOCKSIZE + 4);
+               rect.ymin = cursor[1] - (NODE_SOCKSIZE + 4);
+               rect.xmax = cursor[0] + (NODE_SOCKSIZE + 4);
+               rect.ymax = cursor[1] + (NODE_SOCKSIZE + 4);
                
                if (!(node->flag & NODE_HIDDEN)) {
                        /* extra padding inside and out - allow dragging on the text areas too */
@@ -1087,9 +1176,9 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
        bNodeTree *ntree = snode->edittree;
        bNode *node, *newnode, *lastnode;
        bNodeLink *link, *newlink, *lastlink;
-       int keep_inputs = RNA_boolean_get(op->ptr, "keep_inputs");
+       const bool keep_inputs = RNA_boolean_get(op->ptr, "keep_inputs");
        
-       ED_preview_kill_jobs(C);
+       ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
        
        lastnode = ntree->nodes.last;
        for (node = ntree->nodes.first; node; node = node->next) {
@@ -1162,9 +1251,9 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
                        /* has been set during copy above */
                        newnode = node->new_node;
                        
-                       nodeSetSelected(node, FALSE);
+                       nodeSetSelected(node, false);
                        node->flag &= ~NODE_ACTIVE;
-                       nodeSetSelected(newnode, TRUE);
+                       nodeSetSelected(newnode, true);
                }
                
                /* make sure we don't copy new nodes again! */
@@ -1172,7 +1261,7 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
                        break;
        }
        
-       ntreeUpdateTree(snode->edittree);
+       ntreeUpdateTree(CTX_data_main(C), snode->edittree);
        
        snode_notify(C, snode);
        snode_dag_update(C, snode);
@@ -1189,7 +1278,7 @@ void NODE_OT_duplicate(wmOperatorType *ot)
        
        /* api callbacks */
        ot->exec = node_duplicate_exec;
-       ot->poll = ED_operator_node_active;
+       ot->poll = ED_operator_node_editable;
        
        /* flags */
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1197,7 +1286,7 @@ void NODE_OT_duplicate(wmOperatorType *ot)
        RNA_def_boolean(ot->srna, "keep_inputs", 0, "Keep Inputs", "Keep the input links to duplicated nodes");
 }
 
-int ED_node_select_check(ListBase *lb)
+bool ED_node_select_check(ListBase *lb)
 
 
 {
@@ -1205,11 +1294,11 @@ int ED_node_select_check(ListBase *lb)
 
        for (node = lb->first; node; node = node->next) {
                if (node->flag & NODE_SELECT) {
-                       return TRUE;
+                       return true;
                }
        }
 
-       return FALSE;
+       return false;
 }
 
 /* ******************************** */
@@ -1224,7 +1313,7 @@ static int node_read_renderlayers_exec(bContext *C, wmOperator *UNUSED(op))
        Scene *curscene = CTX_data_scene(C), *scene;
        bNode *node;
 
-       ED_preview_kill_jobs(C);
+       ED_preview_kill_jobs(CTX_wm_manager(C), bmain);
 
        /* first tag scenes unread */
        for (scene = bmain->scene.first; scene; scene = scene->id.next)
@@ -1325,7 +1414,6 @@ int node_render_changed_exec(bContext *C, wmOperator *UNUSED(op))
                        
                        return OPERATOR_FINISHED;
                }
-                  
        }
        return OPERATOR_CANCELLED;
 }
@@ -1361,7 +1449,7 @@ static void node_flag_toggle_exec(SpaceNode *snode, int toggle_flag)
                        
                        if (toggle_flag == NODE_PREVIEW && (node->typeinfo->flag & NODE_PREVIEW) == 0)
                                continue;
-                       if (toggle_flag == NODE_OPTIONS && (node->typeinfo->flag & NODE_OPTIONS) == 0)
+                       if (toggle_flag == NODE_OPTIONS && !(node->typeinfo->draw_buttons || node->typeinfo->draw_buttons_ex))
                                continue;
                        
                        if (node->flag & toggle_flag)
@@ -1375,7 +1463,7 @@ static void node_flag_toggle_exec(SpaceNode *snode, int toggle_flag)
                        
                        if (toggle_flag == NODE_PREVIEW && (node->typeinfo->flag & NODE_PREVIEW) == 0)
                                continue;
-                       if (toggle_flag == NODE_OPTIONS && (node->typeinfo->flag & NODE_OPTIONS) == 0)
+                       if (toggle_flag == NODE_OPTIONS && !(node->typeinfo->draw_buttons || node->typeinfo->draw_buttons_ex))
                                continue;
                        
                        if ((tot_eq && tot_neq) || tot_eq == 0)
@@ -1424,7 +1512,7 @@ static int node_preview_toggle_exec(bContext *C, wmOperator *UNUSED(op))
        if ((snode == NULL) || (snode->edittree == NULL))
                return OPERATOR_CANCELLED;
 
-       ED_preview_kill_jobs(C);
+       ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
 
        node_flag_toggle_exec(snode, NODE_PREVIEW);
 
@@ -1488,7 +1576,7 @@ static int node_socket_toggle_exec(bContext *C, wmOperator *UNUSED(op))
        if ((snode == NULL) || (snode->edittree == NULL))
                return OPERATOR_CANCELLED;
 
-       ED_preview_kill_jobs(C);
+       ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
 
        /* Toggle for all selected nodes */
        hidden = 0;
@@ -1507,7 +1595,7 @@ static int node_socket_toggle_exec(bContext *C, wmOperator *UNUSED(op))
                }
        }
 
-       ntreeUpdateTree(snode->edittree);
+       ntreeUpdateTree(CTX_data_main(C), snode->edittree);
 
        WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, NULL);
 
@@ -1536,7 +1624,7 @@ static int node_mute_exec(bContext *C, wmOperator *UNUSED(op))
        SpaceNode *snode = CTX_wm_space_node(C);
        bNode *node;
 
-       ED_preview_kill_jobs(C);
+       ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
 
        for (node = snode->edittree->nodes.first; node; node = node->next) {
                /* Only allow muting of nodes having a mute func! */
@@ -1561,7 +1649,7 @@ void NODE_OT_mute_toggle(wmOperatorType *ot)
        
        /* callbacks */
        ot->exec = node_mute_exec;
-       ot->poll = ED_operator_node_active;
+       ot->poll = ED_operator_node_editable;
        
        /* flags */
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1574,19 +1662,19 @@ static int node_delete_exec(bContext *C, wmOperator *UNUSED(op))
        SpaceNode *snode = CTX_wm_space_node(C);
        bNode *node, *next;
        
-       ED_preview_kill_jobs(C);
+       ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
 
        for (node = snode->edittree->nodes.first; node; node = next) {
                next = node->next;
                if (node->flag & SELECT) {
                        /* check id user here, nodeFreeNode is called for free dbase too */
                        if (node->id)
-                               node->id->us--;
+                               id_us_min(node->id);
                        nodeFreeNode(snode->edittree, node);
                }
        }
        
-       ntreeUpdateTree(snode->edittree);
+       ntreeUpdateTree(CTX_data_main(C), snode->edittree);
 
        snode_notify(C, snode);
        snode_dag_update(C, snode);
@@ -1603,19 +1691,67 @@ void NODE_OT_delete(wmOperatorType *ot)
        
        /* api callbacks */
        ot->exec = node_delete_exec;
-       ot->poll = ED_operator_node_active;
+       ot->poll = ED_operator_node_editable;
        
        /* flags */
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 }
 
+/* ****************** Switch View ******************* */
+
+static int node_switch_view_poll(bContext *C)
+{
+       SpaceNode *snode = CTX_wm_space_node(C);
+
+       if (snode && snode->edittree)
+               return true;
+
+       return false;
+}
+
+static int node_switch_view_exec(bContext *C, wmOperator *UNUSED(op))
+{
+       SpaceNode *snode = CTX_wm_space_node(C);
+       bNode *node, *next;
+
+       for (node = snode->edittree->nodes.first; node; node = next) {
+               next = node->next;
+               if (node->flag & SELECT) {
+                       /* call the update function from the Switch View node */
+                       node->update = NODE_UPDATE_OPERATOR;
+               }
+       }
+
+       ntreeUpdateTree(CTX_data_main(C), snode->edittree);
+
+       snode_notify(C, snode);
+       snode_dag_update(C, snode);
+
+       return OPERATOR_FINISHED;
+}
+
+void NODE_OT_switch_view_update(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Update Views";
+       ot->description = "Update views of selected node";
+       ot->idname = "NODE_OT_switch_view_update";
+
+       /* api callbacks */
+       ot->exec = node_switch_view_exec;
+       ot->poll = node_switch_view_poll;
+
+       /* flags */
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
 /* ****************** Delete with reconnect ******************* */
 static int node_delete_reconnect_exec(bContext *C, wmOperator *UNUSED(op))
 {
        SpaceNode *snode = CTX_wm_space_node(C);
        bNode *node, *next;
 
-       ED_preview_kill_jobs(C);
+       ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
 
        for (node = snode->edittree->nodes.first; node; node = next) {
                next = node->next;
@@ -1624,12 +1760,12 @@ static int node_delete_reconnect_exec(bContext *C, wmOperator *UNUSED(op))
                        
                        /* check id user here, nodeFreeNode is called for free dbase too */
                        if (node->id)
-                               node->id->us--;
+                               id_us_min(node->id);
                        nodeFreeNode(snode->edittree, node);
                }
        }
 
-       ntreeUpdateTree(snode->edittree);
+       ntreeUpdateTree(CTX_data_main(C), snode->edittree);
 
        snode_notify(C, snode);
        snode_dag_update(C, snode);
@@ -1646,7 +1782,7 @@ void NODE_OT_delete_reconnect(wmOperatorType *ot)
 
        /* api callbacks */
        ot->exec = node_delete_reconnect_exec;
-       ot->poll = ED_operator_node_active;
+       ot->poll = ED_operator_node_editable;
 
        /* flags */
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1659,16 +1795,22 @@ static int node_output_file_add_socket_exec(bContext *C, wmOperator *op)
 {
        Scene *scene = CTX_data_scene(C);
        SpaceNode *snode = CTX_wm_space_node(C);
-       PointerRNA ptr;
-       bNodeTree *ntree;
-       bNode *node;
+       PointerRNA ptr = CTX_data_pointer_get(C, "node");
+       bNodeTree *ntree = NULL;
+       bNode *node = NULL;
        char file_path[MAX_NAME];
 
-       ptr = CTX_data_pointer_get(C, "node");
-       if (!ptr.data)
+       if (ptr.data) {
+               node = ptr.data;
+               ntree = ptr.id.data;
+       }
+       else if (snode && snode->edittree) {
+               ntree = snode->edittree;
+               node = nodeGetActive(snode->edittree);
+       }
+
+       if (!node || node->type != CMP_NODE_OUTPUT_FILE)
                return OPERATOR_CANCELLED;
-       node = ptr.data;
-       ntree = ptr.id.data;
 
        RNA_string_get(op->ptr, "file_path", file_path);
        ntreeCompositOutputFileAddSocket(ntree, node, file_path, &scene->r.im_format);
@@ -1687,7 +1829,7 @@ void NODE_OT_output_file_add_socket(wmOperatorType *ot)
 
        /* callbacks */
        ot->exec = node_output_file_add_socket_exec;
-       ot->poll = composite_node_active;
+       ot->poll = composite_node_editable;
 
        /* flags */
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1701,13 +1843,20 @@ static int node_output_file_remove_active_socket_exec(bContext *C, wmOperator *U
 {
        SpaceNode *snode = CTX_wm_space_node(C);
        PointerRNA ptr = CTX_data_pointer_get(C, "node");
-       bNodeTree *ntree;
-       bNode *node;
+       bNodeTree *ntree = NULL;
+       bNode *node = NULL;
        
-       if (!ptr.data)
+       if (ptr.data) {
+               node = ptr.data;
+               ntree = ptr.id.data;
+       }
+       else if (snode && snode->edittree) {
+               ntree = snode->edittree;
+               node = nodeGetActive(snode->edittree);
+       }
+
+       if (!node || node->type != CMP_NODE_OUTPUT_FILE)
                return OPERATOR_CANCELLED;
-       node = ptr.data;
-       ntree = ptr.id.data;
        
        if (!ntreeCompositOutputFileRemoveActiveSocket(ntree, node))
                return OPERATOR_CANCELLED;
@@ -1726,7 +1875,7 @@ void NODE_OT_output_file_remove_active_socket(wmOperatorType *ot)
        
        /* callbacks */
        ot->exec = node_output_file_remove_active_socket_exec;
-       ot->poll = composite_node_active;
+       ot->poll = composite_node_editable;
        
        /* flags */
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1738,14 +1887,19 @@ static int node_output_file_move_active_socket_exec(bContext *C, wmOperator *op)
 {
        SpaceNode *snode = CTX_wm_space_node(C);
        PointerRNA ptr = CTX_data_pointer_get(C, "node");
-       bNode *node;
+       bNode *node = NULL;
        NodeImageMultiFile *nimf;
        bNodeSocket *sock;
        int direction;
        
-       if (!ptr.data)
+       if (ptr.data)
+               node = ptr.data;
+       else if (snode && snode->edittree)
+               node = nodeGetActive(snode->edittree);
+
+       if (!node || node->type != CMP_NODE_OUTPUT_FILE)
                return OPERATOR_CANCELLED;
-       node = ptr.data;
+
        nimf = node->storage;
        
        sock = BLI_findlink(&node->inputs, nimf->active_input);
@@ -1791,7 +1945,7 @@ void NODE_OT_output_file_move_active_socket(wmOperatorType *ot)
        
        /* callbacks */
        ot->exec = node_output_file_move_active_socket_exec;
-       ot->poll = composite_node_active;
+       ot->poll = composite_node_editable;
        
        /* flags */
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1839,7 +1993,7 @@ void NODE_OT_node_copy_color(wmOperatorType *ot)
 
        /* api callbacks */
        ot->exec = node_copy_color_exec;
-       ot->poll = ED_operator_node_active;
+       ot->poll = ED_operator_node_editable;
 
        /* flags */
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -1854,7 +2008,7 @@ static int node_clipboard_copy_exec(bContext *C, wmOperator *UNUSED(op))
        bNode *node;
        bNodeLink *link, *newlink;
 
-       ED_preview_kill_jobs(C);
+       ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
 
        /* clear current clipboard */
        BKE_node_clipboard_clear();
@@ -1934,14 +2088,14 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op)
        bNodeLink *link;
        int num_nodes;
        float center[2];
-       int is_clipboard_valid;
+       bool is_clipboard_valid, all_nodes_valid;
 
        /* validate pointers in the clipboard */
        is_clipboard_valid = BKE_node_clipboard_validate();
        clipboard_nodes_lb = BKE_node_clipboard_get_nodes();
        clipboard_links_lb = BKE_node_clipboard_get_links();
 
-       if (clipboard_nodes_lb->first == NULL) {
+       if (BLI_listbase_is_empty(clipboard_nodes_lb)) {
                BKE_report(op->reports, RPT_ERROR, "Clipboard is empty");
                return OPERATOR_CANCELLED;
        }
@@ -1952,11 +2106,22 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op)
        }
 
        /* only warn */
-       if (is_clipboard_valid == FALSE) {
+       if (is_clipboard_valid == false) {
                BKE_report(op->reports, RPT_WARNING, "Some nodes references could not be restored, will be left empty");
        }
 
-       ED_preview_kill_jobs(C);
+       /* make sure all clipboard nodes would be valid in the target tree */
+       all_nodes_valid = true;
+       for (node = clipboard_nodes_lb->first; node; node = node->next) {
+               if (!node->typeinfo->poll_instance(node, ntree)) {
+                       all_nodes_valid = false;
+                       BKE_reportf(op->reports, RPT_ERROR, "Cannot add node %s into node tree %s", node->name, ntree->id.name + 2);
+               }
+       }
+       if (!all_nodes_valid)
+               return OPERATOR_CANCELLED;
+
+       ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
 
        /* deselect old nodes */
        node_deselect_all(snode);
@@ -1977,7 +2142,7 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op)
                id_us_plus(node->id);
 
                /* pasted nodes are selected */
-               nodeSetSelected(new_node, TRUE);
+               nodeSetSelected(new_node, true);
        }
        
        /* reparent copied nodes */
@@ -1992,7 +2157,7 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op)
                            link->tonode->new_node, link->tosock->new_sock);
        }
 
-       ntreeUpdateTree(snode->edittree);
+       ntreeUpdateTree(CTX_data_main(C), snode->edittree);
 
        snode_notify(C, snode);
        snode_dag_update(C, snode);
@@ -2000,17 +2165,6 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op)
        return OPERATOR_FINISHED;
 }
 
-static int node_clipboard_paste_invoke(bContext *C, wmOperator *op, const wmEvent *event)
-{
-       ARegion *ar = CTX_wm_region(C);
-       SpaceNode *snode = CTX_wm_space_node(C);
-
-       /* convert mouse coordinates to v2d space */
-       UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &snode->cursor[0], &snode->cursor[1]);
-
-       return node_clipboard_paste_exec(C, op);
-}
-
 void NODE_OT_clipboard_paste(wmOperatorType *ot)
 {
        /* identifiers */
@@ -2020,8 +2174,7 @@ void NODE_OT_clipboard_paste(wmOperatorType *ot)
 
        /* api callbacks */
        ot->exec = node_clipboard_paste_exec;
-       ot->invoke = node_clipboard_paste_invoke;
-       ot->poll = ED_operator_node_active;
+       ot->poll = ED_operator_node_editable;
 
        /* flags */
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -2077,7 +2230,7 @@ static int ntree_socket_add_exec(bContext *C, wmOperator *op)
        /* make the new socket active */
        sock->flag |= SELECT;
        
-       ntreeUpdateTree(ntree);
+       ntreeUpdateTree(CTX_data_main(C), ntree);
 
        WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, NULL);
        
@@ -2093,12 +2246,12 @@ void NODE_OT_tree_socket_add(wmOperatorType *ot)
        
        /* api callbacks */
        ot->exec = ntree_socket_add_exec;
-       ot->poll = ED_operator_node_active;
+       ot->poll = ED_operator_node_editable;
        
        /* flags */
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
        
-       RNA_def_enum(ot->srna, "in_out", node_socket_in_out_items, SOCK_IN, "Socket Type", "");
+       RNA_def_enum(ot->srna, "in_out", rna_enum_node_socket_in_out_items, SOCK_IN, "Socket Type", "");
 }
 
 /********************** Remove interface socket operator *********************/
@@ -2123,7 +2276,7 @@ static int ntree_socket_remove_exec(bContext *C, wmOperator *UNUSED(op))
        if (active_sock)
                active_sock->flag |= SELECT;
        
-       ntreeUpdateTree(ntree);
+       ntreeUpdateTree(CTX_data_main(C), ntree);
 
        WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, NULL);
        
@@ -2139,7 +2292,7 @@ void NODE_OT_tree_socket_remove(wmOperatorType *ot)
        
        /* api callbacks */
        ot->exec = ntree_socket_remove_exec;
-       ot->poll = ED_operator_node_active;
+       ot->poll = ED_operator_node_editable;
        
        /* flags */
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -2171,27 +2324,29 @@ static int ntree_socket_move_exec(bContext *C, wmOperator *op)
                return OPERATOR_CANCELLED;
        
        switch (direction) {
-       case 1: {       /* up */
-               bNodeSocket *before = iosock->prev;
-               BLI_remlink(lb, iosock);
-               if (before)
-                       BLI_insertlinkbefore(lb, before, iosock);
-               else
-                       BLI_addhead(lb, iosock);
-               break;
-       }
-       case 2: {       /* down */
-               bNodeSocket *after = iosock->next;
-               BLI_remlink(lb, iosock);
-               if (after)
-                       BLI_insertlinkafter(lb, after, iosock);
-               else
-                       BLI_addtail(lb, iosock);
-               break;
-       }
+               case 1:
+               {       /* up */
+                       bNodeSocket *before = iosock->prev;
+                       BLI_remlink(lb, iosock);
+                       if (before)
+                               BLI_insertlinkbefore(lb, before, iosock);
+                       else
+                               BLI_addhead(lb, iosock);
+                       break;
+               }
+               case 2:
+               {       /* down */
+                       bNodeSocket *after = iosock->next;
+                       BLI_remlink(lb, iosock);
+                       if (after)
+                               BLI_insertlinkafter(lb, after, iosock);
+                       else
+                               BLI_addtail(lb, iosock);
+                       break;
+               }
        }
        
-       ntreeUpdateTree(ntree);
+       ntreeUpdateTree(CTX_data_main(C), ntree);
 
        WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, NULL);
        
@@ -2207,7 +2362,7 @@ void NODE_OT_tree_socket_move(wmOperatorType *ot)
        
        /* api callbacks */
        ot->exec = ntree_socket_move_exec;
-       ot->poll = ED_operator_node_active;
+       ot->poll = ED_operator_node_editable;
        
        /* flags */
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -2221,6 +2376,7 @@ static int node_shader_script_update_poll(bContext *C)
 {
        Scene *scene = CTX_data_scene(C);
        RenderEngineType *type = RE_engines_find(scene->r.engine);
+       SpaceNode *snode = CTX_wm_space_node(C);
        bNode *node;
        Text *text;
 
@@ -2230,11 +2386,15 @@ static int node_shader_script_update_poll(bContext *C)
 
        /* see if we have a shader script node in context */
        node = CTX_data_pointer_get_type(C, "node", &RNA_ShaderNodeScript).data;
+
+       if (!node && snode && snode->edittree)
+               node = nodeGetActive(snode->edittree);
+
        if (node && node->type == SH_NODE_SCRIPT) {
                NodeShaderScript *nss = node->storage;
 
                if (node->id || nss->filepath[0]) {
-                       return 1;
+                       return ED_operator_node_editable(C);
                }
        }
 
@@ -2249,12 +2409,12 @@ static int node_shader_script_update_poll(bContext *C)
 }
 
 /* recursively check for script nodes in groups using this text and update */
-static int node_shader_script_update_text_recursive(RenderEngine *engine, RenderEngineType *type, bNodeTree *ntree, Text *text)
+static bool node_shader_script_update_text_recursive(RenderEngine *engine, RenderEngineType *type, bNodeTree *ntree, Text *text)
 {
-       int found = FALSE;
+       bool found = false;
        bNode *node;
        
-       ntree->done = TRUE;
+       ntree->done = true;
        
        /* update each script that is using this text datablock */
        for (node = ntree->nodes.first; node; node = node->next) {
@@ -2265,7 +2425,7 @@ static int node_shader_script_update_text_recursive(RenderEngine *engine, Render
                }
                else if (node->type == SH_NODE_SCRIPT && node->id == &text->id) {
                        type->update_script_node(engine, ntree, node);
-                       found = TRUE;
+                       found = true;
                }
        }
        
@@ -2276,24 +2436,34 @@ static int node_shader_script_update_exec(bContext *C, wmOperator *op)
 {
        Main *bmain = CTX_data_main(C);
        Scene *scene = CTX_data_scene(C);
+       SpaceNode *snode = CTX_wm_space_node(C);
        PointerRNA nodeptr = CTX_data_pointer_get_type(C, "node", &RNA_ShaderNodeScript);
+       bNodeTree *ntree = NULL;
+       bNode *node = NULL;
        RenderEngine *engine;
        RenderEngineType *type;
-       int found = FALSE;
+       bool found = false;
 
        /* setup render engine */
        type = RE_engines_find(scene->r.engine);
        engine = RE_engine_create(type);
        engine->reports = op->reports;
 
+       /* get node */
        if (nodeptr.data) {
-               /* update single node */
-               bNodeTree *ntree = nodeptr.id.data;
-               bNode *node = nodeptr.data;
+               ntree = nodeptr.id.data;
+               node = nodeptr.data;
+       }
+       else if (snode && snode->edittree) {
+               ntree = snode->edittree;
+               node = nodeGetActive(snode->edittree);
+       }
 
+       if (node) {
+               /* update single node */
                type->update_script_node(engine, ntree, node);
 
-               found = TRUE;
+               found = true;
        }
        else {
                /* update all nodes using text datablock */
@@ -2303,7 +2473,7 @@ static int node_shader_script_update_exec(bContext *C, wmOperator *op)
                        /* clear flags for recursion check */
                        FOREACH_NODETREE(bmain, ntree, id) {
                                if (ntree->type == NTREE_SHADER)
-                                       ntree->done = FALSE;
+                                       ntree->done = false;
                        } FOREACH_NODETREE_END
                        
                        FOREACH_NODETREE(bmain, ntree, id) {
@@ -2320,7 +2490,7 @@ static int node_shader_script_update_exec(bContext *C, wmOperator *op)
 
        RE_engine_free(engine);
 
-       return (found)? OPERATOR_FINISHED: OPERATOR_CANCELLED;
+       return (found) ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
 }
 
 void NODE_OT_shader_script_update(wmOperatorType *ot)
@@ -2359,7 +2529,7 @@ static int viewer_border_exec(bContext *C, wmOperator *op)
        void *lock;
        ImBuf *ibuf;
 
-       ED_preview_kill_jobs(C);
+       ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
 
        ima = BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
        ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
@@ -2367,7 +2537,7 @@ static int viewer_border_exec(bContext *C, wmOperator *op)
        if (ibuf) {
                ARegion *ar = CTX_wm_region(C);
                SpaceNode *snode = CTX_wm_space_node(C);
-               bNodeTree *btree = snode->edittree;
+               bNodeTree *btree = snode->nodetree;
                rcti rect;
                rctf rectf;
 
@@ -2396,14 +2566,6 @@ static int viewer_border_exec(bContext *C, wmOperator *op)
                                btree->flag &= ~NTREE_VIEWER_BORDER;
                        }
                        else {
-                               if (ibuf->rect)
-                                       memset(ibuf->rect, 0, 4 * ibuf->x * ibuf->y);
-
-                               if (ibuf->rect_float)
-                                       memset(ibuf->rect_float, 0, 4 * ibuf->x * ibuf->y * sizeof(float));
-
-                               ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
-
                                btree->flag |= NTREE_VIEWER_BORDER;
                        }
 
@@ -2438,5 +2600,32 @@ void NODE_OT_viewer_border(wmOperatorType *ot)
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
        /* properties */
-       WM_operator_properties_gesture_border(ot, TRUE);
+       WM_operator_properties_gesture_border(ot, true);
+}
+
+static int clear_viewer_border_exec(bContext *C, wmOperator *UNUSED(op))
+{
+       SpaceNode *snode = CTX_wm_space_node(C);
+       bNodeTree *btree = snode->nodetree;
+
+       btree->flag &= ~NTREE_VIEWER_BORDER;
+       snode_notify(C, snode);
+       WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, NULL);
+
+       return OPERATOR_FINISHED;
+}
+
+void NODE_OT_clear_viewer_border(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Clear Viewer Border";
+       ot->description = "Clear the boundaries for viewer operations";
+       ot->idname = "NODE_OT_clear_viewer_border";
+
+       /* api callbacks */
+       ot->exec = clear_viewer_border_exec;
+       ot->poll = composite_node_active;
+
+       /* flags */
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 }