Cleanup: use `rna_enum_` prefix for RNA enums
[blender.git] / source / blender / editors / space_node / node_edit.c
index 89fa58cd75041e482e9bc2f64a3894627ed10153..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"
@@ -99,10 +90,9 @@ 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;
 
@@ -171,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 */
@@ -185,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)
@@ -211,18 +200,9 @@ static void compo_initjob(void *cjv)
 }
 
 /* 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)
@@ -232,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;
@@ -257,9 +237,17 @@ static void compo_startjob(void *cjv, short *stop, short *do_update, float *prog
        ntree->udh = cj;
 
        // XXX BIF_store_spare();
-       
        /* 1 is do_previews */
-       ntreeCompositExecTree(ntree, &cj->scene->r, FALSE, TRUE, &scene->view_settings, &scene->display_settings);
+
+       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;
@@ -278,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) {
@@ -285,21 +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);
@@ -329,21 +320,6 @@ int composite_node_editable(bContext *C)
        return 0;
 }
 
-static int has_nodetree(bNodeTree *ntree, bNodeTree *lookup)
-{
-       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;
-       
-       return 0;
-}
-
 void snode_dag_update(bContext *C, SpaceNode *snode)
 {
        Main *bmain = CTX_data_main(C);
@@ -351,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
        }
@@ -361,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)
@@ -379,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);
 }
@@ -510,13 +494,9 @@ void ED_node_composit_default(const bContext *C, struct Scene *sce)
        
        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 */
@@ -577,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;
@@ -604,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)
@@ -631,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) {
@@ -654,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;
@@ -674,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);
                        }
 
@@ -705,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);
                                                }
                                        }
                                }
@@ -739,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,
@@ -760,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)
@@ -857,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;
@@ -886,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;
@@ -964,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;
@@ -993,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)
@@ -1059,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;
@@ -1071,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 */
@@ -1148,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) {
@@ -1223,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! */
@@ -1258,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)
 
 
 {
@@ -1266,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;
 }
 
 /* ******************************** */
@@ -1285,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)
@@ -1386,7 +1414,6 @@ int node_render_changed_exec(bContext *C, wmOperator *UNUSED(op))
                        
                        return OPERATOR_FINISHED;
                }
-                  
        }
        return OPERATOR_CANCELLED;
 }
@@ -1422,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->uifunc || node->typeinfo->uifuncbut))
+                       if (toggle_flag == NODE_OPTIONS && !(node->typeinfo->draw_buttons || node->typeinfo->draw_buttons_ex))
                                continue;
                        
                        if (node->flag & toggle_flag)
@@ -1436,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->uifunc || node->typeinfo->uifuncbut))
+                       if (toggle_flag == NODE_OPTIONS && !(node->typeinfo->draw_buttons || node->typeinfo->draw_buttons_ex))
                                continue;
                        
                        if ((tot_eq && tot_neq) || tot_eq == 0)
@@ -1485,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);
 
@@ -1549,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;
@@ -1597,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! */
@@ -1635,14 +1662,14 @@ 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);
                }
        }
@@ -1670,13 +1697,61 @@ void NODE_OT_delete(wmOperatorType *ot)
        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;
@@ -1685,7 +1760,7 @@ 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);
                }
        }
@@ -1734,7 +1809,7 @@ static int node_output_file_add_socket_exec(bContext *C, wmOperator *op)
                node = nodeGetActive(snode->edittree);
        }
 
-       if (!node)
+       if (!node || node->type != CMP_NODE_OUTPUT_FILE)
                return OPERATOR_CANCELLED;
 
        RNA_string_get(op->ptr, "file_path", file_path);
@@ -1780,7 +1855,7 @@ static int node_output_file_remove_active_socket_exec(bContext *C, wmOperator *U
                node = nodeGetActive(snode->edittree);
        }
 
-       if (!node)
+       if (!node || node->type != CMP_NODE_OUTPUT_FILE)
                return OPERATOR_CANCELLED;
        
        if (!ntreeCompositOutputFileRemoveActiveSocket(ntree, node))
@@ -1822,7 +1897,7 @@ static int node_output_file_move_active_socket_exec(bContext *C, wmOperator *op)
        else if (snode && snode->edittree)
                node = nodeGetActive(snode->edittree);
 
-       if (!node)
+       if (!node || node->type != CMP_NODE_OUTPUT_FILE)
                return OPERATOR_CANCELLED;
 
        nimf = node->storage;
@@ -1933,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();
@@ -2013,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, all_nodes_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;
        }
@@ -2031,22 +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");
        }
 
        /* make sure all clipboard nodes would be valid in the target tree */
-       all_nodes_valid = TRUE;
+       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;
+                       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(C);
+       ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C));
 
        /* deselect old nodes */
        node_deselect_all(snode);
@@ -2067,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 */
@@ -2090,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 */
@@ -2110,7 +2174,6 @@ 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_editable;
 
        /* flags */
@@ -2188,7 +2251,7 @@ void NODE_OT_tree_socket_add(wmOperatorType *ot)
        /* 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 *********************/
@@ -2261,24 +2324,26 @@ 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(CTX_data_main(C), ntree);
@@ -2344,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) {
@@ -2360,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;
                }
        }
        
@@ -2377,7 +2442,7 @@ static int node_shader_script_update_exec(bContext *C, wmOperator *op)
        bNode *node = NULL;
        RenderEngine *engine;
        RenderEngineType *type;
-       int found = FALSE;
+       bool found = false;
 
        /* setup render engine */
        type = RE_engines_find(scene->r.engine);
@@ -2398,7 +2463,7 @@ static int node_shader_script_update_exec(bContext *C, wmOperator *op)
                /* update single node */
                type->update_script_node(engine, ntree, node);
 
-               found = TRUE;
+               found = true;
        }
        else {
                /* update all nodes using text datablock */
@@ -2408,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) {
@@ -2464,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);
@@ -2501,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;
                        }
 
@@ -2543,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;
 }