diff options
Diffstat (limited to 'source/blender/windowmanager/intern/wm_jobs.c')
-rw-r--r-- | source/blender/windowmanager/intern/wm_jobs.c | 119 |
1 files changed, 99 insertions, 20 deletions
diff --git a/source/blender/windowmanager/intern/wm_jobs.c b/source/blender/windowmanager/intern/wm_jobs.c index 343b1f68c7f..3ebfac4928c 100644 --- a/source/blender/windowmanager/intern/wm_jobs.c +++ b/source/blender/windowmanager/intern/wm_jobs.c @@ -26,6 +26,8 @@ * ***** END GPL LICENSE BLOCK ***** */ +#include <string.h> + #include "DNA_windowmanager_types.h" #include "MEM_guardedalloc.h" @@ -89,12 +91,14 @@ struct wmJob { /* to prevent cpu overhead, use this one which only gets called when job really starts, not in thread */ void (*initjob)(void *); /* this runs inside thread, and does full job */ - void (*startjob)(void *, short *stop, short *do_update); + void (*startjob)(void *, short *stop, short *do_update, float *progress); /* update gets called if thread defines so, and max once per timerstep */ /* it runs outside thread, blocking blender, no drawing! */ void (*update)(void *); /* free entire customdata, doesn't run in thread */ void (*free)(void *); + /* gets called when job is stopped, not in thread */ + void (*endjob)(void *); /* running jobs each have own timer */ double timestep; @@ -107,6 +111,10 @@ struct wmJob { void *owner; int flag; short suspended, running, ready, do_update, stop; + float progress; + + /* for display in header, identification */ + char name[128]; /* once running, we store this separately */ void *run_customdata; @@ -117,18 +125,32 @@ struct wmJob { }; +/* finds: + * 1st priority: job with same owner and name + * 2nd priority: job with same owner + */ +static wmJob *wm_job_find(wmWindowManager *wm, void *owner, char *name) +{ + wmJob *steve, *found=NULL; + + for(steve= wm->jobs.first; steve; steve= steve->next) + if(steve->owner==owner) { + found= steve; + if (name && strcmp(steve->name, name)==0) + return steve; + } + + return found; +} + /* ******************* public API ***************** */ /* returns current or adds new job, but doesnt run it */ /* every owner only gets a single job, adding a new one will stop running stop and when stopped it starts the new one */ -wmJob *WM_jobs_get(wmWindowManager *wm, wmWindow *win, void *owner, int flag) +wmJob *WM_jobs_get(wmWindowManager *wm, wmWindow *win, void *owner, char *name, int flag) { - wmJob *steve; - - for(steve= wm->jobs.first; steve; steve= steve->next) - if(steve->owner==owner) - break; + wmJob *steve= wm_job_find(wm, owner, name); if(steve==NULL) { steve= MEM_callocN(sizeof(wmJob), "new job"); @@ -137,6 +159,7 @@ wmJob *WM_jobs_get(wmWindowManager *wm, wmWindow *win, void *owner, int flag) steve->win= win; steve->owner= owner; steve->flag= flag; + BLI_strncpy(steve->name, name, sizeof(steve->name)); } return steve; @@ -154,6 +177,26 @@ int WM_jobs_test(wmWindowManager *wm, void *owner) return 0; } +float WM_jobs_progress(wmWindowManager *wm, void *owner) +{ + wmJob *steve= wm_job_find(wm, owner, NULL); + + if (steve && steve->flag & WM_JOB_PROGRESS) + return steve->progress; + + return 0.0; +} + +char *WM_jobs_name(wmWindowManager *wm, void *owner) +{ + wmJob *steve= wm_job_find(wm, owner, NULL); + + if (steve) + return steve->name; + + return NULL; +} + void WM_jobs_customdata(wmJob *steve, void *customdata, void (*free)(void *)) { /* pending job? just free */ @@ -177,20 +220,22 @@ void WM_jobs_timer(wmJob *steve, double timestep, unsigned int note, unsigned in } void WM_jobs_callbacks(wmJob *steve, - void (*startjob)(void *, short *, short *), + void (*startjob)(void *, short *, short *, float *), void (*initjob)(void *), - void (*update)(void *)) + void (*update)(void *), + void (*endjob)(void *)) { steve->startjob= startjob; steve->initjob= initjob; steve->update= update; + steve->endjob= endjob; } static void *do_job_thread(void *job_v) { wmJob *steve= job_v; - steve->startjob(steve->run_customdata, &steve->stop, &steve->do_update); + steve->startjob(steve->run_customdata, &steve->stop, &steve->do_update, &steve->progress); steve->ready= 1; return NULL; @@ -244,6 +289,7 @@ void WM_jobs_start(wmWindowManager *wm, wmJob *steve) steve->stop= 0; steve->ready= 0; + steve->progress= 0.0; BLI_init_threads(&steve->threads, do_job_thread, 1); BLI_insert_thread(&steve->threads, steve); @@ -266,6 +312,9 @@ static void wm_jobs_kill_job(wmWindowManager *wm, wmJob *steve) /* signal job to end */ steve->stop= 1; BLI_end_threads(&steve->threads); + + if(steve->endjob) + steve->endjob(steve->run_customdata); } if(steve->wt) @@ -290,28 +339,32 @@ void WM_jobs_stop_all(wmWindowManager *wm) } -/* signal job(s) from this owner to stop, timer is required to get handled */ -void WM_jobs_stop(wmWindowManager *wm, void *owner) +/* signal job(s) from this owner or callback to stop, timer is required to get handled */ +void WM_jobs_stop(wmWindowManager *wm, void *owner, void *startjob) { wmJob *steve; for(steve= wm->jobs.first; steve; steve= steve->next) - if(steve->owner==owner) + if(steve->owner==owner || steve->startjob==startjob) if(steve->running) steve->stop= 1; } /* actually terminate thread and job timer */ -void WM_jobs_kill(wmWindowManager *wm, void *owner) +void WM_jobs_kill(wmWindowManager *wm, void *owner, void *startjob) { wmJob *steve; - for(steve= wm->jobs.first; steve; steve= steve->next) - if(steve->owner==owner) - break; - - if (steve) - wm_jobs_kill_job(wm, steve); + steve= wm->jobs.first; + while(steve) { + if(steve->owner==owner || steve->startjob==startjob) { + wmJob* bill = steve; + steve= steve->next; + wm_jobs_kill_job(wm, bill); + } else { + steve= steve->next; + } + } } @@ -332,6 +385,9 @@ void wm_jobs_timer_ended(wmWindowManager *wm, wmTimer *wt) void wm_jobs_timer(const bContext *C, wmWindowManager *wm, wmTimer *wt) { wmJob *steve= wm->jobs.first, *stevenext; + float total_progress= 0.f; + float jobs_progress=0; + for(; steve; steve= stevenext) { stevenext= steve->next; @@ -347,10 +403,16 @@ void wm_jobs_timer(const bContext *C, wmWindowManager *wm, wmTimer *wt) steve->update(steve->run_customdata); if(steve->note) WM_event_add_notifier(C, steve->note, NULL); + + if (steve->flag & WM_JOB_PROGRESS) + WM_event_add_notifier(C, NC_WM|ND_JOB, NULL); steve->do_update= 0; } if(steve->ready) { + if(steve->endjob) + steve->endjob(steve->run_customdata); + /* free own data */ steve->run_free(steve->run_customdata); steve->run_customdata= NULL; @@ -365,6 +427,8 @@ void wm_jobs_timer(const bContext *C, wmWindowManager *wm, wmTimer *wt) if(steve->endnote) WM_event_add_notifier(C, steve->endnote, NULL); + WM_event_add_notifier(C, NC_WM|ND_JOB, NULL); + /* new job added for steve? */ if(steve->customdata) { WM_jobs_start(wm, steve); @@ -377,6 +441,10 @@ void wm_jobs_timer(const bContext *C, wmWindowManager *wm, wmTimer *wt) BLI_remlink(&wm->jobs, steve); MEM_freeN(steve); } + } else if (steve->flag & WM_JOB_PROGRESS) { + /* accumulate global progress for running jobs */ + jobs_progress++; + total_progress += steve->progress; } } else if(steve->suspended) { @@ -384,5 +452,16 @@ void wm_jobs_timer(const bContext *C, wmWindowManager *wm, wmTimer *wt) } } } + + /* on file load 'winactive' can be NULL, possibly it should not happen but for now do a NULL check - campbell */ + if(wm->winactive) { + /* if there are running jobs, set the global progress indicator */ + if (jobs_progress > 0) { + float progress = total_progress / (float)jobs_progress; + WM_progress_set(wm->winactive, progress); + } else { + WM_progress_clear(wm->winactive); + } + } } |