bugfix [#23663] relative path dind work on linux
[blender.git] / source / blender / editors / space_image / image_ops.c
index 897b02404ef6f949c02f288770604ee0c786e0fb..11b39af2e03e1e36f1d07e63ecdd4e1966d84c52 100644 (file)
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  *
  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
  * All rights reserved.
  *
- * Contributor(s): Blender Foundation, 2002-2009
+ * Contributor(s): Blender Foundation, 2002-2009, Xavier Thomas
  *
  * ***** END GPL LICENSE BLOCK *****
  */
 
+#include <stddef.h>
 #include <string.h>
 #include <stdlib.h>
+#include <errno.h>
 
 #include "MEM_guardedalloc.h"
 
-#include "DNA_image_types.h"
-#include "DNA_node_types.h"
 #include "DNA_object_types.h"
+#include "DNA_node_types.h"
 #include "DNA_packedFile_types.h"
-#include "DNA_space_types.h"
 #include "DNA_scene_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_userdef_types.h"
-#include "DNA_windowmanager_types.h"
 
 #include "BKE_colortools.h"
 #include "BKE_context.h"
 #include "BKE_image.h"
 #include "BKE_global.h"
 #include "BKE_library.h"
+#include "BKE_main.h"
 #include "BKE_node.h"
 #include "BKE_packedFile.h"
 #include "BKE_report.h"
@@ -60,7 +58,6 @@
 
 #include "RNA_access.h"
 #include "RNA_define.h"
-#include "RNA_types.h"
 #include "RNA_enum_types.h"
 
 #include "ED_image.h"
@@ -108,12 +105,14 @@ static void sima_zoom_set_factor(SpaceImage *sima, ARegion *ar, float zoomfac)
        sima_zoom_set(sima, ar, sima->zoom*zoomfac);
 }
 
+#if 0 // currently unused
 static int image_poll(bContext *C)
 {
        return (CTX_data_edit_image(C) != NULL);
 }
+#endif
 
-static int space_image_poll(bContext *C)
+static int space_image_buffer_exists_poll(bContext *C)
 {
        SpaceImage *sima= CTX_wm_space_image(C);
        if(sima && sima->spacetype==SPACE_IMAGE)
@@ -124,14 +123,19 @@ static int space_image_poll(bContext *C)
 
 static int space_image_file_exists_poll(bContext *C)
 {
-       if(space_image_poll(C)) {
+       if(space_image_buffer_exists_poll(C)) {
                SpaceImage *sima= CTX_wm_space_image(C);
                ImBuf *ibuf;
                void *lock;
-               int poll;
-               
+               int poll= 0;
+               char name[FILE_MAX];
+
                ibuf= ED_space_image_acquire_buffer(sima, &lock);
-               poll= (ibuf && BLI_exists(ibuf->name) && BLI_is_writable(ibuf->name));
+               if(ibuf) {
+                       BLI_strncpy(name, ibuf->name, FILE_MAX);
+                       BLI_path_abs(name, G.sce);
+                       poll= (BLI_exists(name) && BLI_is_writable(name));
+               }
                ED_space_image_release_buffer(sima, lock);
 
                return poll;
@@ -139,6 +143,13 @@ static int space_image_file_exists_poll(bContext *C)
        return 0;
 }
 
+static int space_image_poll(bContext *C)
+{
+       SpaceImage *sima= CTX_wm_space_image(C);
+       if(sima && sima->spacetype==SPACE_IMAGE && sima->image)
+               return 1;
+       return 0;
+}
 
 int space_image_main_area_poll(bContext *C)
 {
@@ -182,7 +193,7 @@ static void view_pan_exit(bContext *C, wmOperator *op, int cancel)
        if(cancel) {
                sima->xof= vpd->xof;
                sima->yof= vpd->yof;
-               ED_area_tag_redraw(CTX_wm_area(C));
+               ED_region_tag_redraw(CTX_wm_region(C));
        }
 
        WM_cursor_restore(CTX_wm_window(C));
@@ -198,7 +209,7 @@ static int view_pan_exec(bContext *C, wmOperator *op)
        sima->xof += offset[0];
        sima->yof += offset[1];
 
-       ED_area_tag_redraw(CTX_wm_area(C));
+       ED_region_tag_redraw(CTX_wm_region(C));
 
        /* XXX notifier? */
 #if 0
@@ -214,8 +225,21 @@ static int view_pan_exec(bContext *C, wmOperator *op)
 
 static int view_pan_invoke(bContext *C, wmOperator *op, wmEvent *event)
 {
-       view_pan_init(C, op, event);
-       return OPERATOR_RUNNING_MODAL;
+       if (event->type == MOUSEPAN) {
+               SpaceImage *sima= CTX_wm_space_image(C);
+               float offset[2];
+               
+               offset[0]= (event->x - event->prevx)/sima->zoom;
+               offset[1]= (event->y - event->prevy)/sima->zoom;
+               RNA_float_set_array(op->ptr, "offset", offset);
+
+               view_pan_exec(C, op);
+               return OPERATOR_FINISHED;
+       }
+       else {
+               view_pan_init(C, op, event);
+               return OPERATOR_RUNNING_MODAL;
+       }
 }
 
 static int view_pan_modal(bContext *C, wmOperator *op, wmEvent *event)
@@ -301,7 +325,7 @@ static void view_zoom_exit(bContext *C, wmOperator *op, int cancel)
 
        if(cancel) {
                sima->zoom= vpd->zoom;
-               ED_area_tag_redraw(CTX_wm_area(C));
+               ED_region_tag_redraw(CTX_wm_region(C));
        }
 
        WM_cursor_restore(CTX_wm_window(C));
@@ -315,7 +339,7 @@ static int view_zoom_exec(bContext *C, wmOperator *op)
 
        sima_zoom_set_factor(sima, ar, RNA_float_get(op->ptr, "factor"));
 
-       ED_area_tag_redraw(CTX_wm_area(C));
+       ED_region_tag_redraw(CTX_wm_region(C));
 
        /* XXX notifier? */
 #if 0
@@ -331,8 +355,22 @@ static int view_zoom_exec(bContext *C, wmOperator *op)
 
 static int view_zoom_invoke(bContext *C, wmOperator *op, wmEvent *event)
 {
-       view_zoom_init(C, op, event);
-       return OPERATOR_RUNNING_MODAL;
+       if (event->type == MOUSEZOOM) {
+               SpaceImage *sima= CTX_wm_space_image(C);
+               ARegion *ar= CTX_wm_region(C);
+               float factor;
+               
+               factor= 1.0 + (event->x-event->prevx+event->y-event->prevy)/300.0f;
+               RNA_float_set(op->ptr, "factor", factor);
+               sima_zoom_set(sima, ar, sima->zoom*factor);
+               ED_region_tag_redraw(CTX_wm_region(C));
+               
+               return OPERATOR_FINISHED;
+       }
+       else {
+               view_zoom_init(C, op, event);
+               return OPERATOR_RUNNING_MODAL;
+       }
 }
 
 static int view_zoom_modal(bContext *C, wmOperator *op, wmEvent *event)
@@ -347,7 +385,7 @@ static int view_zoom_modal(bContext *C, wmOperator *op, wmEvent *event)
                        factor= 1.0 + (vpd->x-event->x+vpd->y-event->y)/300.0f;
                        RNA_float_set(op->ptr, "factor", factor);
                        sima_zoom_set(sima, ar, vpd->zoom*factor);
-                       ED_area_tag_redraw(CTX_wm_area(C));
+                       ED_region_tag_redraw(CTX_wm_region(C));
                        break;
                case MIDDLEMOUSE:
                case LEFTMOUSE:
@@ -430,7 +468,7 @@ static int view_all_exec(bContext *C, wmOperator *op)
 
        sima->xof= sima->yof= 0.0f;
 
-       ED_area_tag_redraw(CTX_wm_area(C));
+       ED_region_tag_redraw(CTX_wm_region(C));
        
        return OPERATOR_FINISHED;
 }
@@ -482,11 +520,16 @@ static int view_selected_exec(bContext *C, wmOperator *op)
        if(size<=0.01) size= 0.01;
        sima_zoom_set(sima, ar, 0.7/size);
 
-       ED_area_tag_redraw(CTX_wm_area(C));
+       ED_region_tag_redraw(CTX_wm_region(C));
        
        return OPERATOR_FINISHED;
 }
 
+static int view_selected_poll(bContext *C)
+{
+       return (space_image_main_area_poll(C) && ED_operator_uvedit(C));
+}
+
 void IMAGE_OT_view_selected(wmOperatorType *ot)
 {
        /* identifiers */
@@ -495,7 +538,7 @@ void IMAGE_OT_view_selected(wmOperatorType *ot)
        
        /* api callbacks */
        ot->exec= view_selected_exec;
-       ot->poll= ED_operator_uvedit;
+       ot->poll= view_selected_poll;
 }
 
 /********************** view zoom in/out operator *********************/
@@ -507,7 +550,7 @@ static int view_zoom_in_exec(bContext *C, wmOperator *op)
 
        sima_zoom_set_factor(sima, ar, 1.25f);
 
-       ED_area_tag_redraw(CTX_wm_area(C));
+       ED_region_tag_redraw(CTX_wm_region(C));
        
        return OPERATOR_FINISHED;
 }
@@ -530,7 +573,7 @@ static int view_zoom_out_exec(bContext *C, wmOperator *op)
 
        sima_zoom_set_factor(sima, ar, 0.8f);
 
-       ED_area_tag_redraw(CTX_wm_area(C));
+       ED_region_tag_redraw(CTX_wm_region(C));
        
        return OPERATOR_FINISHED;
 }
@@ -568,7 +611,7 @@ static int view_zoom_ratio_exec(bContext *C, wmOperator *op)
        }
 #endif
 
-       ED_area_tag_redraw(CTX_wm_area(C));
+       ED_region_tag_redraw(CTX_wm_region(C));
        
        return OPERATOR_FINISHED;
 }
@@ -601,11 +644,16 @@ static const EnumPropertyItem image_file_type_items[] = {
                {R_JP2, "JPEG_2000", 0, "Jpeg 2000", ""},
 #endif
                {R_IRIS, "IRIS", 0, "Iris", ""},
-       //if(G.have_libtiff)
+#ifdef WITH_TIFF
                {R_TIFF, "TIFF", 0, "Tiff", ""},
+#endif
+#ifdef WITH_DDS
                {R_RADHDR, "RADIANCE_HDR", 0, "Radiance HDR", ""},
+#endif
+#ifdef WITH_CINEON
                {R_CINEON, "CINEON", 0, "Cineon", ""},
                {R_DPX, "DPX", 0, "DPX", ""},
+#endif
 #ifdef WITH_OPENEXR
                {R_OPENEXR, "OPENEXR", 0, "OpenEXR", ""},
        /* saving sequences of multilayer won't work, they copy buffers  */
@@ -617,7 +665,7 @@ static const EnumPropertyItem image_file_type_items[] = {
 
 static void image_filesel(bContext *C, wmOperator *op, const char *path)
 {
-       RNA_string_set(op->ptr, "path", path);
+       RNA_string_set(op->ptr, "filepath", path);
        WM_event_add_fileselect(C, op); 
 }
 
@@ -648,11 +696,16 @@ static int open_exec(bContext *C, wmOperator *op)
        Image *ima= NULL;
        char str[FILE_MAX];
 
-       RNA_string_get(op->ptr, "path", str);
-       ima= BKE_add_image_file(str, scene->r.cfra);
+       RNA_string_get(op->ptr, "filepath", str);
+       /* default to frame 1 if there's no scene in context */
+
+       errno= 0;
+
+       ima= BKE_add_image_file(str, scene ? scene->r.cfra : 1);
 
        if(!ima) {
                if(op->customdata) MEM_freeN(op->customdata);
+               BKE_reportf(op->reports, RPT_ERROR, "Can't read: \"%s\", %s.", str, errno ? strerror(errno) : "Unsupported image format");
                return OPERATOR_CANCELLED;
        }
        
@@ -676,7 +729,8 @@ static int open_exec(bContext *C, wmOperator *op)
 
        // XXX other users?
        BKE_image_signal(ima, (sima)? &sima->iuser: NULL, IMA_SIGNAL_RELOAD);
-
+       WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, ima);
+       
        MEM_freeN(op->customdata);
 
        return OPERATOR_FINISHED;
@@ -685,9 +739,27 @@ static int open_exec(bContext *C, wmOperator *op)
 static int open_invoke(bContext *C, wmOperator *op, wmEvent *event)
 {
        SpaceImage *sima= CTX_wm_space_image(C);
-       char *path= (sima && sima->image)? sima->image->name: U.textudir;
+       char *path=U.textudir;
+       Image *ima= NULL;
+
+       if(sima) {
+                ima= sima->image;
+       }
 
-       if(RNA_property_is_set(op->ptr, "path"))
+       if (ima==NULL) {
+                Tex *tex= CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
+                if(tex && tex->type==TEX_IMAGE)
+                        ima= tex->ima;
+       }
+
+       if(ima)
+               path= ima->name;
+       
+
+       if(!RNA_property_is_set(op->ptr, "relative_path"))
+               RNA_boolean_set(op->ptr, "relative_path", U.flag & USER_RELPATHS);
+
+       if(RNA_property_is_set(op->ptr, "filepath"))
                return open_exec(C, op);
        
        open_init(C, op);
@@ -712,7 +784,7 @@ void IMAGE_OT_open(wmOperatorType *ot)
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 
        /* properties */
-       WM_operator_properties_filesel(ot, FOLDERFILE|IMAGEFILE|MOVIEFILE, FILE_SPECIAL);
+       WM_operator_properties_filesel(ot, FOLDERFILE|IMAGEFILE|MOVIEFILE, FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_FILEPATH|WM_FILESEL_RELPATH);
 }
 
 /******************** replace image operator ********************/
@@ -725,7 +797,7 @@ static int replace_exec(bContext *C, wmOperator *op)
        if(!sima->image)
                return OPERATOR_CANCELLED;
        
-       RNA_string_get(op->ptr, "path", str);
+       RNA_string_get(op->ptr, "filepath", str);
        BLI_strncpy(sima->image->name, str, sizeof(sima->image->name)-1); /* we cant do much if the str is longer then 240 :/ */
 
        BKE_image_signal(sima->image, &sima->iuser, IMA_SIGNAL_RELOAD);
@@ -737,15 +809,17 @@ static int replace_exec(bContext *C, wmOperator *op)
 static int replace_invoke(bContext *C, wmOperator *op, wmEvent *event)
 {
        SpaceImage *sima= CTX_wm_space_image(C);
-       char *path= (sima->image)? sima->image->name: U.textudir;
 
        if(!sima->image)
                return OPERATOR_CANCELLED;
 
-       if(RNA_property_is_set(op->ptr, "path"))
+       if(RNA_property_is_set(op->ptr, "filepath"))
                return replace_exec(C, op);
 
-       image_filesel(C, op, path);
+       if(!RNA_property_is_set(op->ptr, "relative_path"))
+               RNA_boolean_set(op->ptr, "relative_path", (strncmp(sima->image->name, "//", 2))==0);
+
+       image_filesel(C, op, sima->image->name);
 
        return OPERATOR_RUNNING_MODAL;
 }
@@ -765,27 +839,27 @@ void IMAGE_OT_replace(wmOperatorType *ot)
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 
        /* properties */
-       WM_operator_properties_filesel(ot, FOLDERFILE|IMAGEFILE|MOVIEFILE, FILE_SPECIAL);
+       WM_operator_properties_filesel(ot, FOLDERFILE|IMAGEFILE|MOVIEFILE, FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_FILEPATH|WM_FILESEL_RELPATH);
 }
 
 /******************** save image as operator ********************/
 
 /* assumes name is FILE_MAX */
 /* ima->name and ibuf->name should end up the same */
-static void save_image_doit(bContext *C, SpaceImage *sima, Scene *scene, wmOperator *op, char *name)
+static void save_image_doit(bContext *C, SpaceImage *sima, Scene *scene, wmOperator *op, char *path, int do_newpath)
 {
        Image *ima= ED_space_image(sima);
        void *lock;
        ImBuf *ibuf= ED_space_image_acquire_buffer(sima, &lock);
-       int len;
 
-       if (ibuf) {     
-               BLI_convertstringcode(name, G.sce);
-               BLI_convertstringframe(name, scene->r.cfra);
+       if (ibuf) {
+               int relative= (RNA_struct_find_property(op->ptr, "relative_path") && RNA_boolean_get(op->ptr, "relative_path"));
+               int save_copy= (RNA_struct_find_property(op->ptr, "copy") && RNA_boolean_get(op->ptr, "copy"));
+
+               BLI_path_abs(path, G.sce);
                
                if(scene->r.scemode & R_EXTENSION)  {
-                       BKE_add_image_extension(scene, name, sima->imtypenr);
-                       BKE_add_image_extension(scene, name, sima->imtypenr);
+                       BKE_add_image_extension(path, sima->imtypenr);
                }
                
                /* enforce user setting for RGB or RGBA, but skip BW */
@@ -799,54 +873,66 @@ static void save_image_doit(bContext *C, SpaceImage *sima, Scene *scene, wmOpera
                if(sima->imtypenr==R_MULTILAYER) {
                        RenderResult *rr= BKE_image_acquire_renderresult(scene, ima);
                        if(rr) {
-                               RE_WriteRenderResult(rr, name, scene->r.quality);
-                               
-                               BLI_strncpy(ima->name, name, sizeof(ima->name));
-                               BLI_strncpy(ibuf->name, name, sizeof(ibuf->name));
-                               
-                               /* should be function? nevertheless, saving only happens here */
-                               for(ibuf= ima->ibufs.first; ibuf; ibuf= ibuf->next)
-                                       ibuf->userflags &= ~IB_BITMAPDIRTY;
-                               
+                               RE_WriteRenderResult(rr, path, scene->r.quality);
+
+                               if(relative)
+                                       BLI_path_rel(path, G.sce); /* only after saving */
+
+                               if(!save_copy) {
+                                       if(do_newpath) {
+                                               BLI_strncpy(ima->name, path, sizeof(ima->name));
+                                               BLI_strncpy(ibuf->name, path, sizeof(ibuf->name));
+                                       }
+
+                                       /* should be function? nevertheless, saving only happens here */
+                                       for(ibuf= ima->ibufs.first; ibuf; ibuf= ibuf->next)
+                                               ibuf->userflags &= ~IB_BITMAPDIRTY;
+                               }
                        }
                        else
                                BKE_report(op->reports, RPT_ERROR, "Did not write, no Multilayer Image");
                        BKE_image_release_renderresult(scene, ima);
                }
-               else if (BKE_write_ibuf(scene, ibuf, name, sima->imtypenr, scene->r.subimtype, scene->r.quality)) {
-                       BLI_strncpy(ima->name, name, sizeof(ima->name));
-                       BLI_strncpy(ibuf->name, name, sizeof(ibuf->name));
-                       
-                       ibuf->userflags &= ~IB_BITMAPDIRTY;
-                       
-                       /* change type? */
-                       if(ima->type==IMA_TYPE_R_RESULT) {
-                               ima->type= IMA_TYPE_IMAGE;
-
-                               /* workaround to ensure the render result buffer is no longer used
-                                * by this image, otherwise can crash when a new render result is
-                                * created. */
-                               if(ibuf->rect && !(ibuf->mall & IB_rect))
-                                       imb_freerectImBuf(ibuf);
-                               if(ibuf->rect_float && !(ibuf->mall & IB_rectfloat))
-                                       imb_freerectfloatImBuf(ibuf);
-                               if(ibuf->zbuf && !(ibuf->mall & IB_zbuf))
-                                       IMB_freezbufImBuf(ibuf);
-                               if(ibuf->zbuf_float && !(ibuf->mall & IB_zbuffloat))
-                                       IMB_freezbuffloatImBuf(ibuf);
-                       }
-                       if( ELEM(ima->source, IMA_SRC_GENERATED, IMA_SRC_VIEWER)) {
-                               ima->source= IMA_SRC_FILE;
-                               ima->type= IMA_TYPE_IMAGE;
+               else if (BKE_write_ibuf(scene, ibuf, path, sima->imtypenr, scene->r.subimtype, scene->r.quality)) {
+
+                       if(relative)
+                               BLI_path_rel(path, G.sce); /* only after saving */
+
+                       if(!save_copy) {
+                               if(do_newpath) {
+                                       BLI_strncpy(ima->name, path, sizeof(ima->name));
+                                       BLI_strncpy(ibuf->name, path, sizeof(ibuf->name));
+                               }
+
+                               ibuf->userflags &= ~IB_BITMAPDIRTY;
+
+                               /* change type? */
+                               if(ima->type==IMA_TYPE_R_RESULT) {
+                                       ima->type= IMA_TYPE_IMAGE;
+
+                                       /* workaround to ensure the render result buffer is no longer used
+                                        * by this image, otherwise can crash when a new render result is
+                                        * created. */
+                                       if(ibuf->rect && !(ibuf->mall & IB_rect))
+                                               imb_freerectImBuf(ibuf);
+                                       if(ibuf->rect_float && !(ibuf->mall & IB_rectfloat))
+                                               imb_freerectfloatImBuf(ibuf);
+                                       if(ibuf->zbuf && !(ibuf->mall & IB_zbuf))
+                                               IMB_freezbufImBuf(ibuf);
+                                       if(ibuf->zbuf_float && !(ibuf->mall & IB_zbuffloat))
+                                               IMB_freezbuffloatImBuf(ibuf);
+                               }
+                               if( ELEM(ima->source, IMA_SRC_GENERATED, IMA_SRC_VIEWER)) {
+                                       ima->source= IMA_SRC_FILE;
+                                       ima->type= IMA_TYPE_IMAGE;
+                               }
+
+                               /* name image as how we saved it */
+                               rename_id(&ima->id, BLI_path_basename(path));
                        }
-                       
-                       /* name image as how we saved it */
-                       len= strlen(name);
-                       while (len > 0 && name[len - 1] != '/' && name[len - 1] != '\\') len--;
-                       rename_id(&ima->id, name+len);
                } 
                else
-                       BKE_reportf(op->reports, RPT_ERROR, "Couldn't write image: %s", name);
+                       BKE_reportf(op->reports, RPT_ERROR, "Couldn't write image: %s", path);
 
                WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, sima->image);
 
@@ -867,9 +953,9 @@ static int save_as_exec(bContext *C, wmOperator *op)
                return OPERATOR_CANCELLED;
 
        sima->imtypenr= RNA_enum_get(op->ptr, "file_type");
-       RNA_string_get(op->ptr, "path", str);
+       RNA_string_get(op->ptr, "filepath", str);
 
-       save_image_doit(C, sima, scene, op, str);
+       save_image_doit(C, sima, scene, op, str, TRUE);
 
        return OPERATOR_FINISHED;
 }
@@ -882,7 +968,10 @@ static int save_as_invoke(bContext *C, wmOperator *op, wmEvent *event)
        ImBuf *ibuf;
        void *lock;
 
-       if(RNA_property_is_set(op->ptr, "path"))
+       if(!RNA_property_is_set(op->ptr, "relative_path"))
+               RNA_boolean_set(op->ptr, "relative_path", U.flag & USER_RELPATHS);
+
+       if(RNA_property_is_set(op->ptr, "filepath"))
                return save_as_exec(C, op);
        
        if(!ima)
@@ -897,6 +986,8 @@ static int save_as_invoke(bContext *C, wmOperator *op, wmEvent *event)
                        sima->imtypenr= R_MULTILAYER;
                else if(ima->type==IMA_TYPE_R_RESULT)
                        sima->imtypenr= scene->r.imtype;
+               else if (ima->source == IMA_SRC_GENERATED)
+                       sima->imtypenr= R_PNG;
                else
                        sima->imtypenr= BKE_ftype_to_imtype(ibuf->ftype);
 
@@ -904,7 +995,12 @@ static int save_as_invoke(bContext *C, wmOperator *op, wmEvent *event)
                
                if(ibuf->name[0]==0)
                        BLI_strncpy(ibuf->name, G.ima, FILE_MAX);
-               
+
+               /* enable save_copy by default for render results */
+               if(ELEM(ima->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE) && !RNA_property_is_set(op->ptr, "copy")) {
+                       RNA_boolean_set(op->ptr, "copy", TRUE);
+               }
+
                // XXX note: we can give default menu enums to operator for this 
                image_filesel(C, op, ibuf->name);
 
@@ -927,14 +1023,16 @@ void IMAGE_OT_save_as(wmOperatorType *ot)
        /* api callbacks */
        ot->exec= save_as_exec;
        ot->invoke= save_as_invoke;
-       ot->poll= space_image_poll;
+       ot->poll= space_image_buffer_exists_poll;
 
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 
        /* properties */
        RNA_def_enum(ot->srna, "file_type", image_file_type_items, R_PNG, "File Type", "File type to save image as.");
-       WM_operator_properties_filesel(ot, FOLDERFILE|IMAGEFILE|MOVIEFILE, FILE_SPECIAL);
+       WM_operator_properties_filesel(ot, FOLDERFILE|IMAGEFILE|MOVIEFILE, FILE_SPECIAL, FILE_SAVE, WM_FILESEL_FILEPATH|WM_FILESEL_RELPATH);
+
+       RNA_def_boolean(ot->srna, "copy", 0, "Copy", "Create a new image file without modifying the current image in blender");
 }
 
 /******************** save image operator ********************/
@@ -956,9 +1054,11 @@ static int save_exec(bContext *C, wmOperator *op)
 
        /* if exists, saves over without fileselect */
        
-       BLI_strncpy(name, ibuf->name, FILE_MAX);
+       BLI_strncpy(name, ima->name, FILE_MAX);
        if(name[0]==0)
                BLI_strncpy(name, G.ima, FILE_MAX);
+       else
+               BLI_path_abs(name, G.sce);
        
        if(BLI_exists(name) && BLI_is_writable(name)) {
                rr= BKE_image_acquire_renderresult(scene, ima);
@@ -971,7 +1071,7 @@ static int save_exec(bContext *C, wmOperator *op)
                BKE_image_release_renderresult(scene, ima);
                ED_space_image_release_buffer(sima, lock);
                
-               save_image_doit(C, sima, scene, op, name);
+               save_image_doit(C, sima, scene, op, name, FALSE);
        }
        else {
                ED_space_image_release_buffer(sima, lock);
@@ -1044,14 +1144,14 @@ static int save_sequence_exec(bContext *C, wmOperator *op)
                        char name[FILE_MAX];
                        BLI_strncpy(name, ibuf->name, sizeof(name));
                        
-                       BLI_convertstringcode(name, G.sce);
+                       BLI_path_abs(name, G.sce);
 
                        if(0 == IMB_saveiff(ibuf, name, IB_rect | IB_zbuf | IB_zbuffloat)) {
                                BKE_reportf(op->reports, RPT_ERROR, "Could not write image %s.", name);
                                break;
                        }
 
-                       printf("Saved: %s\n", ibuf->name);
+                       BKE_reportf(op->reports, RPT_INFO, "Saved: %s\n", ibuf->name);
                        ibuf->userflags &= ~IB_BITMAPDIRTY;
                }
        }
@@ -1067,7 +1167,7 @@ void IMAGE_OT_save_sequence(wmOperatorType *ot)
        
        /* api callbacks */
        ot->exec= save_sequence_exec;
-       ot->poll= space_image_poll;
+       ot->poll= space_image_buffer_exists_poll;
 
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@@ -1087,7 +1187,6 @@ static int reload_exec(bContext *C, wmOperator *op)
        BKE_image_signal(ima, (sima)? &sima->iuser: NULL, IMA_SIGNAL_RELOAD);
 
        WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, ima);
-       ED_area_tag_redraw(CTX_wm_area(C));
        
        return OPERATOR_FINISHED;
 }
@@ -1100,7 +1199,6 @@ void IMAGE_OT_reload(wmOperatorType *ot)
        
        /* api callbacks */
        ot->exec= reload_exec;
-       ot->poll= image_poll;
 
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@@ -1118,7 +1216,7 @@ static int new_exec(bContext *C, wmOperator *op)
        PropertyRNA *prop;
        char name[22];
        float color[4];
-       int width, height, floatbuf, uvtestgrid;
+       int width, height, floatbuf, uvtestgrid, alpha;
 
        /* retrieve state */
        sima= CTX_wm_space_image(C);
@@ -1131,9 +1229,15 @@ static int new_exec(bContext *C, wmOperator *op)
        floatbuf= RNA_boolean_get(op->ptr, "float");
        uvtestgrid= RNA_boolean_get(op->ptr, "uv_test_grid");
        RNA_float_get_array(op->ptr, "color", color);
-       color[3]= RNA_float_get(op->ptr, "alpha");
+       alpha= RNA_boolean_get(op->ptr, "alpha");
+       
+       if (!floatbuf && scene->r.color_mgt_flag & R_COLOR_MANAGEMENT)
+               linearrgb_to_srgb_v3_v3(color, color);
+
+       if(!alpha)
+               color[3]= 1.0f;
 
-       ima = BKE_add_image_size(width, height, name, floatbuf, uvtestgrid, color);
+       ima = BKE_add_image_size(width, height, name, alpha ? 32 : 24, floatbuf, uvtestgrid, color);
 
        if(!ima)
                return OPERATOR_CANCELLED;
@@ -1161,6 +1265,9 @@ static int new_exec(bContext *C, wmOperator *op)
 
 void IMAGE_OT_new(wmOperatorType *ot)
 {
+       PropertyRNA *prop;
+       static float default_color[4]= {0.0f, 0.0f, 0.0f, 1.0f};
+       
        /* identifiers */
        ot->name= "New";
        ot->idname= "IMAGE_OT_new";
@@ -1176,8 +1283,9 @@ void IMAGE_OT_new(wmOperatorType *ot)
        RNA_def_string(ot->srna, "name", "Untitled", 21, "Name", "Image datablock name.");
        RNA_def_int(ot->srna, "width", 1024, 1, INT_MAX, "Width", "Image width.", 1, 16384);
        RNA_def_int(ot->srna, "height", 1024, 1, INT_MAX, "Height", "Image height.", 1, 16384);
-       RNA_def_float_color(ot->srna, "color", 3, NULL, 0.0f, FLT_MAX, "Color", "Default fill color.", 0.0f, 1.0f);
-       RNA_def_float(ot->srna, "alpha", 1.0f, 0.0f, 1.0f, "Alpha", "Default fill alpha.", 0.0f, 1.0f);
+       prop= RNA_def_float_color(ot->srna, "color", 4, NULL, 0.0f, FLT_MAX, "Color", "Default fill color.", 0.0f, 1.0f);
+       RNA_def_property_float_array_default(prop, default_color);
+       RNA_def_boolean(ot->srna, "alpha", 1, "Alpha", "Create an image with an alpha channel.");
        RNA_def_boolean(ot->srna, "uv_test_grid", 0, "UV Test Grid", "Fill the image with a grid for UV map testing.");
        RNA_def_boolean(ot->srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth.");
 }
@@ -1195,7 +1303,7 @@ static int pack_test(bContext *C, wmOperator *op)
                return 0;
 
        if(ima->source==IMA_SRC_SEQUENCE || ima->source==IMA_SRC_MOVIE) {
-               BKE_report(op->reports, RPT_ERROR, "Can't pack movie or image sequence.");
+               BKE_report(op->reports, RPT_ERROR, "Packing movies or image sequences not supported.");
                return 0;
        }
 
@@ -1221,6 +1329,8 @@ static int pack_exec(bContext *C, wmOperator *op)
        else
                ima->packedfile= newPackedFile(op->reports, ima->name);
 
+       WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, ima);
+       
        return OPERATOR_FINISHED;
 }
 
@@ -1251,12 +1361,12 @@ void IMAGE_OT_pack(wmOperatorType *ot)
 {
        /* identifiers */
        ot->name= "Pack";
+       ot->description= "Pack an image as embedded data into the .blend file"; 
        ot->idname= "IMAGE_OT_pack";
        
        /* api callbacks */
        ot->exec= pack_exec;
        ot->invoke= pack_invoke;
-       ot->poll= space_image_poll;
 
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@@ -1267,12 +1377,14 @@ void IMAGE_OT_pack(wmOperatorType *ot)
 
 /********************* unpack operator *********************/
 
-void unpack_menu(bContext *C, char *opname, char *abs_name, char *folder, PackedFile *pf)
+void unpack_menu(bContext *C, char *opname, Image *ima, char *folder, PackedFile *pf)
 {
+       PointerRNA props_ptr;
        uiPopupMenu *pup;
        uiLayout *layout;
        char line[FILE_MAXDIR + FILE_MAXFILE + 100];
        char local_name[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX];
+       char *abs_name = ima->name;
        
        strcpy(local_name, abs_name);
        BLI_splitdirstring(local_name, fi);
@@ -1281,23 +1393,39 @@ void unpack_menu(bContext *C, char *opname, char *abs_name, char *folder, Packed
        pup= uiPupMenuBegin(C, "Unpack file", 0);
        layout= uiPupMenuLayout(pup);
 
-       uiItemEnumO(layout, "Remove Pack", 0, opname, "method", PF_REMOVE);
+       uiItemEnumO(layout, opname, "Remove Pack", 0, "method", PF_REMOVE);
 
        if(strcmp(abs_name, local_name)) {
                switch(checkPackedFile(local_name, pf)) {
                        case PF_NOFILE:
                                sprintf(line, "Create %s", local_name);
-                               uiItemEnumO(layout, line, 0, opname, "method", PF_WRITE_LOCAL);
+                               props_ptr= uiItemFullO(layout, opname, line, 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+                               RNA_enum_set(&props_ptr, "method", PF_WRITE_LOCAL);
+                               RNA_string_set(&props_ptr, "image", ima->id.name+2);
+       
                                break;
                        case PF_EQUAL:
                                sprintf(line, "Use %s (identical)", local_name);
-                               uiItemEnumO(layout, line, 0, opname, "method", PF_USE_LOCAL);
+                               //uiItemEnumO(layout, opname, line, 0, "method", PF_USE_LOCAL);
+                               props_ptr= uiItemFullO(layout, opname, line, 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+                               RNA_enum_set(&props_ptr, "method", PF_USE_LOCAL);
+                               RNA_string_set(&props_ptr, "image", ima->id.name+2);
+                               
                                break;
                        case PF_DIFFERS:
                                sprintf(line, "Use %s (differs)", local_name);
-                               uiItemEnumO(layout, line, 0, opname, "method", PF_USE_LOCAL);
+                               //uiItemEnumO(layout, opname, line, 0, "method", PF_USE_LOCAL);
+                               props_ptr= uiItemFullO(layout, opname, line, 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+                               RNA_enum_set(&props_ptr, "method", PF_USE_LOCAL);
+                               RNA_string_set(&props_ptr, "image", ima->id.name);
+                               
                                sprintf(line, "Overwrite %s", local_name);
-                               uiItemEnumO(layout, line, 0, opname, "method", PF_WRITE_LOCAL);
+                               //uiItemEnumO(layout, opname, line, 0, "method", PF_WRITE_LOCAL);
+                               props_ptr= uiItemFullO(layout, opname, line, 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+                               RNA_enum_set(&props_ptr, "method", PF_WRITE_LOCAL);
+                               RNA_string_set(&props_ptr, "image", ima->id.name+2);
+                               
+                               
                                break;
                }
        }
@@ -1305,17 +1433,30 @@ void unpack_menu(bContext *C, char *opname, char *abs_name, char *folder, Packed
        switch(checkPackedFile(abs_name, pf)) {
                case PF_NOFILE:
                        sprintf(line, "Create %s", abs_name);
-                       uiItemEnumO(layout, line, 0, opname, "method", PF_WRITE_ORIGINAL);
+                       //uiItemEnumO(layout, opname, line, 0, "method", PF_WRITE_ORIGINAL);
+                       props_ptr= uiItemFullO(layout, opname, line, 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+                       RNA_enum_set(&props_ptr, "method", PF_WRITE_ORIGINAL);
+                       RNA_string_set(&props_ptr, "image", ima->id.name+2);
                        break;
                case PF_EQUAL:
                        sprintf(line, "Use %s (identical)", abs_name);
-                       uiItemEnumO(layout, line, 0, opname, "method", PF_USE_ORIGINAL);
+                       //uiItemEnumO(layout, opname, line, 0, "method", PF_USE_ORIGINAL);
+                       props_ptr= uiItemFullO(layout, opname, line, 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+                       RNA_enum_set(&props_ptr, "method", PF_USE_ORIGINAL);
+                       RNA_string_set(&props_ptr, "image", ima->id.name+2);
                        break;
                case PF_DIFFERS:
                        sprintf(line, "Use %s (differs)", local_name);
-                       uiItemEnumO(layout, line, 0, opname, "method", PF_USE_ORIGINAL);
+                       //uiItemEnumO(layout, opname, line, 0, "method", PF_USE_ORIGINAL);
+                       props_ptr= uiItemFullO(layout, opname, line, 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+                       RNA_enum_set(&props_ptr, "method", PF_USE_ORIGINAL);
+                       RNA_string_set(&props_ptr, "image", ima->id.name+2);
+                       
                        sprintf(line, "Overwrite %s", local_name);
-                       uiItemEnumO(layout, line, 0, opname, "method", PF_WRITE_ORIGINAL);
+                       //uiItemEnumO(layout, opname, line, 0, "method", PF_WRITE_ORIGINAL);
+                       props_ptr= uiItemFullO(layout, opname, line, 0, NULL, WM_OP_EXEC_DEFAULT, UI_ITEM_O_RETURN_PROPS);
+                       RNA_enum_set(&props_ptr, "method", PF_WRITE_ORIGINAL);
+                       RNA_string_set(&props_ptr, "image", ima->id.name+2);
                        break;
        }
 
@@ -1327,18 +1468,28 @@ static int unpack_exec(bContext *C, wmOperator *op)
        Image *ima= CTX_data_edit_image(C);
        int method= RNA_enum_get(op->ptr, "method");
 
+       /* find the suppplied image by name */
+       if (RNA_property_is_set(op->ptr, "image")) {
+               char imaname[22];
+               RNA_string_get(op->ptr, "image", imaname);
+               ima = BLI_findstring(&CTX_data_main(C)->image, imaname, offsetof(ID, name) + 2);
+               if (!ima) ima = CTX_data_edit_image(C);
+       }
+       
        if(!ima || !ima->packedfile)
                return OPERATOR_CANCELLED;
 
        if(ima->source==IMA_SRC_SEQUENCE || ima->source==IMA_SRC_MOVIE) {
-               BKE_report(op->reports, RPT_ERROR, "Can't unpack movie or image sequence.");
+               BKE_report(op->reports, RPT_ERROR, "Unpacking movies or image sequences not supported.");
                return OPERATOR_CANCELLED;
        }
 
        if(G.fileflags & G_AUTOPACK)
                BKE_report(op->reports, RPT_WARNING, "AutoPack is enabled, so image will be packed again on file save.");
-       
+               
        unpackImage(op->reports, ima, method);
+       
+       WM_event_add_notifier(C, NC_IMAGE|NA_EDITED, ima);
 
        return OPERATOR_FINISHED;
 }
@@ -1347,18 +1498,21 @@ static int unpack_invoke(bContext *C, wmOperator *op, wmEvent *event)
 {
        Image *ima= CTX_data_edit_image(C);
 
+       if(RNA_property_is_set(op->ptr, "image"))
+               return unpack_exec(C, op);
+               
        if(!ima || !ima->packedfile)
                return OPERATOR_CANCELLED;
 
        if(ima->source==IMA_SRC_SEQUENCE || ima->source==IMA_SRC_MOVIE) {
-               BKE_report(op->reports, RPT_ERROR, "Can't unpack movie or image sequence.");
+               BKE_report(op->reports, RPT_ERROR, "Unpacking movies or image sequences not supported.");
                return OPERATOR_CANCELLED;
        }
 
        if(G.fileflags & G_AUTOPACK)
                BKE_report(op->reports, RPT_WARNING, "AutoPack is enabled, so image will be packed again on file save.");
        
-       unpack_menu(C, "IMAGE_OT_unpack", ima->name, "textures", ima->packedfile);
+       unpack_menu(C, "IMAGE_OT_unpack", ima, "textures", ima->packedfile);
 
        return OPERATOR_FINISHED;
 }
@@ -1367,18 +1521,19 @@ void IMAGE_OT_unpack(wmOperatorType *ot)
 {
        /* identifiers */
        ot->name= "Unpack";
+       ot->description= "Save an image packed in the .blend file to disk"; 
        ot->idname= "IMAGE_OT_unpack";
        
        /* api callbacks */
        ot->exec= unpack_exec;
        ot->invoke= unpack_invoke;
-       ot->poll= space_image_poll;
 
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 
        /* properties */
        RNA_def_enum(ot->srna, "method", unpack_method_items, PF_USE_LOCAL, "Method", "How to unpack.");
+       RNA_def_string(ot->srna, "image", "", 21, "Image Name", "Image datablock name to unpack.");
 }
 
 /******************** sample image operator ********************/
@@ -1468,7 +1623,7 @@ static void sample_apply(bContext *C, wmOperator *op, wmEvent *event)
                        info->colf[0]= fp[0];
                        info->colf[1]= fp[1];
                        info->colf[2]= fp[2];
-                       info->colf[3]= fp[4];
+                       info->colf[3]= fp[3];
                        info->colfp= info->colf;
                }
 
@@ -1588,6 +1743,116 @@ void IMAGE_OT_sample(wmOperatorType *ot)
        ot->flag= OPTYPE_BLOCKING;
 }
 
+/******************** sample line operator ********************/
+static int sample_line_exec(bContext *C, wmOperator *op)
+{
+       SpaceImage *sima= CTX_wm_space_image(C);
+       ARegion *ar= CTX_wm_region(C);
+       Scene *scene= CTX_data_scene(C);
+       
+       int x_start= RNA_int_get(op->ptr, "xstart");
+       int y_start= RNA_int_get(op->ptr, "ystart");
+       int x_end= RNA_int_get(op->ptr, "xend");
+       int y_end= RNA_int_get(op->ptr, "yend");
+       
+       void *lock;
+       ImBuf *ibuf= ED_space_image_acquire_buffer(sima, &lock);
+       Histogram *hist= &sima->sample_line_hist;
+       
+       float x1f, y1f, x2f, y2f;
+       int x1, y1, x2, y2;
+       int i, x, y;
+       float *fp;
+       float rgb[3];
+       unsigned char *cp;
+       
+       if (ibuf == NULL) {
+               ED_space_image_release_buffer(sima, lock);
+               return OPERATOR_CANCELLED;
+       }
+       /* hmmmm */
+       if (ibuf->channels < 3) {
+               ED_space_image_release_buffer(sima, lock);
+               return OPERATOR_CANCELLED;
+       }
+       
+       UI_view2d_region_to_view(&ar->v2d, x_start, y_start, &x1f, &y1f);
+       UI_view2d_region_to_view(&ar->v2d, x_end, y_end, &x2f, &y2f);
+       x1= 0.5f+ x1f*ibuf->x;
+       x2= 0.5f+ x2f*ibuf->x;
+       y1= 0.5f+ y1f*ibuf->y;
+       y2= 0.5f+ y2f*ibuf->y;
+       
+       hist->channels = 3;
+       hist->x_resolution = 256;
+       hist->xmax = 1.0f;
+       hist->ymax = 1.0f;
+       
+       for (i=0; i<256; i++) {
+               x= (int)(0.5f + x1 + (float)i*(x2-x1)/255.0f);
+               y= (int)(0.5f + y1 + (float)i*(y2-y1)/255.0f);
+               
+               if (x<0 || y<0 || x>=ibuf->x || y>=ibuf->y) {
+                       hist->data_luma[i] = hist->data_r[i] = hist->data_g[i]= hist->data_b[i] = 0.0f;
+               } else {
+                       if (ibuf->rect_float) {
+                               fp= (ibuf->rect_float + (ibuf->channels)*(y*ibuf->x + x));
+
+                               if (scene->r.color_mgt_flag & R_COLOR_MANAGEMENT)
+                                       linearrgb_to_srgb_v3_v3(rgb, fp);
+                               else
+                                       copy_v3_v3(rgb, fp);
+
+                               hist->data_r[i] = rgb[0];
+                               hist->data_g[i] = rgb[1];
+                               hist->data_b[i] = rgb[2];
+                               hist->data_luma[i] = (0.299f*rgb[0] + 0.587f*rgb[1] + 0.114f*rgb[2]);
+                       }
+                       else if (ibuf->rect) {
+                               cp= (unsigned char *)(ibuf->rect + y*ibuf->x + x);
+                               hist->data_r[i] = (float)cp[0]/255.0f;
+                               hist->data_g[i] = (float)cp[1]/255.0f;
+                               hist->data_b[i] = (float)cp[2]/255.0f;
+                               hist->data_luma[i] = (0.299f*cp[0] + 0.587f*cp[1] + 0.114f*cp[2])/255;
+                       }
+               }
+       }
+       
+       ED_space_image_release_buffer(sima, lock);
+       
+       ED_area_tag_redraw(CTX_wm_area(C));
+       
+       return OPERATOR_FINISHED;
+}
+
+static int sample_line_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+       SpaceImage *sima= CTX_wm_space_image(C);
+       
+       if(!ED_space_image_has_buffer(sima))
+               return OPERATOR_CANCELLED;
+       
+       return WM_gesture_straightline_invoke(C, op, event);
+}
+
+void IMAGE_OT_sample_line(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Sample Line";
+       ot->idname= "IMAGE_OT_sample_line";
+       
+       /* api callbacks */
+       ot->invoke= sample_line_invoke;
+       ot->modal= WM_gesture_straightline_modal;
+       ot->exec= sample_line_exec;
+       ot->poll= space_image_main_area_poll;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT);
+}
+
 /******************** set curve point operator ********************/
 
 void IMAGE_OT_curves_point_set(wmOperatorType *ot)
@@ -1760,52 +2025,107 @@ void IMAGE_OT_record_composite(wmOperatorType *ot)
        ot->invoke= record_composite_invoke;
        ot->modal= record_composite_modal;
        ot->cancel= record_composite_cancel;
-       ot->poll= space_image_poll;
+       ot->poll= space_image_buffer_exists_poll;
+}
+
+/********************* cycle render slot operator *********************/
+
+static int cycle_render_slot_poll(bContext *C)
+{
+       Image *ima= CTX_data_edit_image(C);
+
+       return (ima && ima->type == IMA_TYPE_R_RESULT);
+}
+
+static int cycle_render_slot_exec(bContext *C, wmOperator *op)
+{
+       Image *ima= CTX_data_edit_image(C);
+       int a, slot, cur= ima->render_slot;
+
+       for(a=1; a<IMA_MAX_RENDER_SLOT; a++) {
+               slot= (cur+a)%IMA_MAX_RENDER_SLOT;
+
+               if(ima->renders[slot] || slot == ima->last_render_slot) {
+                       ima->render_slot= slot;
+                       break;
+               }
+       }
+
+       if(a == IMA_MAX_RENDER_SLOT)
+               ima->render_slot= ((cur == 1)? 0: 1);
+       
+       WM_event_add_notifier(C, NC_IMAGE|ND_DRAW, NULL);
+
+       return OPERATOR_FINISHED;
+}
+
+void IMAGE_OT_cycle_render_slot(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Cycle Render Slot";
+       ot->idname= "IMAGE_OT_cycle_render_slot";
+       
+       /* api callbacks */
+       ot->exec= cycle_render_slot_exec;
+       ot->poll= cycle_render_slot_poll;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 }
 
 /******************** TODO ********************/
 
 /* XXX notifier? */
-#if 0
+
 /* goes over all ImageUsers, and sets frame numbers if auto-refresh is set */
-void BIF_image_update_frame(void)
+
+void ED_image_update_frame(const bContext *C)
 {
+       Main *mainp= CTX_data_main(C);
+       Scene *scene= CTX_data_scene(C);
+       wmWindowManager *wm= CTX_wm_manager(C);
+       wmWindow *win;
        Tex *tex;
        
        /* texture users */
-       for(tex= G.main->tex.first; tex; tex= tex->id.next) {
-               if(tex->type==TEX_IMAGE && tex->ima)
-                       if(ELEM(tex->ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE))
+       for(tex= mainp->tex.first; tex; tex= tex->id.next) {
+               if(tex->type==TEX_IMAGE && tex->ima) {
+                       if(ELEM(tex->ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) {
                                if(tex->iuser.flag & IMA_ANIM_ALWAYS)
-                                       BKE_image_user_calc_imanr(&tex->iuser, scene->r.cfra, 0);
-               
+                                       BKE_image_user_calc_frame(&tex->iuser, scene->r.cfra, 0);
+                       }
+               }
        }
+       
        /* image window, compo node users */
-       if(G.curscreen) {
-               ScrArea *sa;
-               for(sa= G.curscreen->areabase.first; sa; sa= sa->next) {
-                       if(sa->spacetype==SPACE_VIEW3D) {
-                               View3D *v3d= sa->spacedata.first;
-                               if(v3d->bgpic)
-                                       if(v3d->bgpic->iuser.flag & IMA_ANIM_ALWAYS)
-                                               BKE_image_user_calc_imanr(&v3d->bgpic->iuser, scene->r.cfra, 0);
-                       }
-                       else if(sa->spacetype==SPACE_IMAGE) {
-                               SpaceImage *sima= sa->spacedata.first;
-                               if(sima->iuser.flag & IMA_ANIM_ALWAYS)
-                                       BKE_image_user_calc_imanr(&sima->iuser, scene->r.cfra, 0);
-                       }
-                       else if(sa->spacetype==SPACE_NODE) {
-                               SpaceNode *snode= sa->spacedata.first;
-                               if((snode->treetype==NTREE_COMPOSIT) && (snode->nodetree)) {
-                                       bNode *node;
-                                       for(node= snode->nodetree->nodes.first; node; node= node->next) {
-                                               if(node->id && node->type==CMP_NODE_IMAGE) {
-                                                       Image *ima= (Image *)node->id;
-                                                       ImageUser *iuser= node->storage;
-                                                       if(ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE))
-                                                               if(iuser->flag & IMA_ANIM_ALWAYS)
-                                                                       BKE_image_user_calc_imanr(iuser, scene->r.cfra, 0);
+       if(wm) {
+               for(win= wm->windows.first; win; win= win->next) {
+                       ScrArea *sa;
+                       for(sa= win->screen->areabase.first; sa; sa= sa->next) {
+                               if(sa->spacetype==SPACE_VIEW3D) {
+                                       View3D *v3d= sa->spacedata.first;
+                                       BGpic *bgpic;
+                                       for(bgpic= v3d->bgpicbase.first; bgpic; bgpic= bgpic->next)
+                                               if(bgpic->iuser.flag & IMA_ANIM_ALWAYS)
+                                                       BKE_image_user_calc_frame(&bgpic->iuser, scene->r.cfra, 0);
+                               }
+                               else if(sa->spacetype==SPACE_IMAGE) {
+                                       SpaceImage *sima= sa->spacedata.first;
+                                       if(sima->iuser.flag & IMA_ANIM_ALWAYS)
+                                               BKE_image_user_calc_frame(&sima->iuser, scene->r.cfra, 0);
+                               }
+                               else if(sa->spacetype==SPACE_NODE) {
+                                       SpaceNode *snode= sa->spacedata.first;
+                                       if((snode->treetype==NTREE_COMPOSIT) && (snode->nodetree)) {
+                                               bNode *node;
+                                               for(node= snode->nodetree->nodes.first; node; node= node->next) {
+                                                       if(node->id && node->type==CMP_NODE_IMAGE) {
+                                                               Image *ima= (Image *)node->id;
+                                                               ImageUser *iuser= node->storage;
+                                                               if(ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE))
+                                                                       if(iuser->flag & IMA_ANIM_ALWAYS)
+                                                                               BKE_image_user_calc_frame(iuser, scene->r.cfra, 0);
+                                                       }
                                                }
                                        }
                                }
@@ -1813,5 +2133,4 @@ void BIF_image_update_frame(void)
                }
        }
 }
-#endif