Beispiel #1
0
void dt_lua_lock()
{
  if(!darktable.lua_state.ending && pthread_equal(darktable.control->gui_thread, pthread_self()) != 0)
  {
    dt_print(DT_DEBUG_LUA, "LUA WARNING locking from the gui thread should be avoided\n");
    //g_assert(false);
  }

  dt_pthread_mutex_lock(&darktable.lua_state.mutex);
}
Beispiel #2
0
static gboolean _dt_ctl_log_message_timeout_callback(gpointer data)
{
  dt_pthread_mutex_lock(&darktable.control->log_mutex);
  if(darktable.control->log_ack != darktable.control->log_pos)
    darktable.control->log_ack = (darktable.control->log_ack + 1) % DT_CTL_LOG_SIZE;
  darktable.control->log_message_timeout_id = 0;
  dt_pthread_mutex_unlock(&darktable.control->log_mutex);
  dt_control_queue_redraw_center();
  return FALSE;
}
Beispiel #3
0
void dt_control_progress_set_progress(dt_control_t *control, dt_progress_t *progress, double value)
{
  // set the value
  dt_pthread_mutex_lock(&progress->mutex);
  progress->progress = value;
  dt_pthread_mutex_unlock(&progress->mutex);

  // tell the gui
  dt_pthread_mutex_lock(&control->progress_system.mutex);
  if(control->progress_system.proxy.module != NULL)
    control->progress_system.proxy.updated(control->progress_system.proxy.module, progress->gui_data, value);
  dt_pthread_mutex_unlock(&control->progress_system.mutex);

#ifdef HAVE_UNITY
  if(progress->has_progress_bar)
    unity_launcher_entry_set_progress(progress->darktable_launcher, CLAMP(value, 0, 1.0));
#endif

}
Beispiel #4
0
void dt_lua_init_lock()
{
  pthread_mutexattr_t a;
  pthread_mutexattr_init(&a);
  pthread_mutexattr_settype(&a, PTHREAD_MUTEX_RECURSIVE);
  dt_pthread_mutex_init(&darktable.lua_state.mutex, &a);
  pthread_mutexattr_destroy(&a);
  // we want our lock initialized locked
  dt_pthread_mutex_lock(&darktable.lua_state.mutex);
}
Beispiel #5
0
void dt_dev_module_remove(dt_develop_t *dev, dt_iop_module_t *module)
{
  //if(darktable.gui->reset) return;
  dt_pthread_mutex_lock(&dev->history_mutex);
  int del = 0;
  if(dev->gui_attached)
  {
    int nb = g_list_length(dev->history);
    int pos = 0;
    for (int i=0; i<nb; i++)
    {
      GList *elem = g_list_nth(dev->history,pos);

      dt_dev_history_item_t *hist = (dt_dev_history_item_t *)(elem->data);

      if (module->instance == hist->module->instance && module->multi_priority == hist->module->multi_priority)
      {
        free(hist->params);
        free(hist->blend_params);
        free(hist);
        dev->history = g_list_delete_link(dev->history, elem);
        dev->history_end--;
        del = 1;
      }
      else
      {
        pos++;
      }
    }
  }

  dt_pthread_mutex_unlock(&dev->history_mutex);

  //and we remove it from the list
  GList *modules = g_list_first(dev->iop);
  while(modules)
  {
    dt_iop_module_t *mod = (dt_iop_module_t *)modules->data;
    if(mod == module)
    {
      dev->iop = g_list_remove_link(dev->iop,modules);
      break;
    }
    modules = g_list_next(modules);
  }

  if(dev->gui_attached && del)
  {
    /* signal that history has changed */
    dt_control_signal_raise(darktable.signals, DT_SIGNAL_DEVELOP_HISTORY_CHANGE);
    /* redraw */
    dt_control_queue_redraw_center();
  }

}
Beispiel #6
0
void gui_update(struct dt_iop_module_t *self)
{
  dt_iop_exposure_gui_data_t *g = (dt_iop_exposure_gui_data_t *)self->gui_data;
  dt_iop_exposure_params_t *p = (dt_iop_exposure_params_t *)self->params;

  if(!dt_image_is_raw(&self->dev->image_storage))
  {
    gtk_widget_hide(GTK_WIDGET(g->mode));
    p->mode = EXPOSURE_MODE_MANUAL;
    dt_dev_add_history_item(darktable.develop, self, TRUE);
  }
  else
  {
    gtk_widget_show(GTK_WIDGET(g->mode));
  }

  dt_bauhaus_combobox_set(g->mode, g_list_index(g->modes, GUINT_TO_POINTER(p->mode)));

  dt_bauhaus_slider_set_soft(g->black, p->black);
  dt_bauhaus_slider_set_soft(g->exposure, p->exposure);

  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->autoexp), FALSE);
  dt_bauhaus_slider_set(g->autoexpp, 0.01);
  gtk_widget_set_sensitive(GTK_WIDGET(g->autoexpp), FALSE);

  dt_bauhaus_slider_set(g->deflicker_percentile, p->deflicker_percentile);
  dt_bauhaus_slider_set(g->deflicker_target_level, p->deflicker_target_level);
  dt_bauhaus_combobox_set(
      g->deflicker_histogram_source,
      g_list_index(g->deflicker_histogram_sources, GUINT_TO_POINTER(p->deflicker_histogram_source)));

  self->request_color_pick = DT_REQUEST_COLORPICK_OFF;

  free(g->deflicker_histogram);
  g->deflicker_histogram = NULL;

  gtk_label_set_text(g->deflicker_used_EC, "");
  dt_pthread_mutex_lock(&g->lock);
  g->deflicker_computed_exposure = NAN;
  dt_pthread_mutex_unlock(&g->lock);

  switch(p->mode)
  {
    case EXPOSURE_MODE_DEFLICKER:
      autoexp_disable(self);
      gtk_stack_set_visible_child_name(GTK_STACK(g->mode_stack), "deflicker");
      if(p->deflicker_histogram_source == DEFLICKER_HISTOGRAM_SOURCE_SOURCEFILE)
        deflicker_prepare_histogram(self, &g->deflicker_histogram, &g->deflicker_histogram_stats);
      break;
    case EXPOSURE_MODE_MANUAL:
    default:
      gtk_stack_set_visible_child_name(GTK_STACK(g->mode_stack), "manual");
      break;
  }
}
Beispiel #7
0
void _camera_configuration_update(const dt_camctl_t *c,const dt_camera_t *camera)
{
// dt_camctl_t *camctl=(dt_camctl_t *)c;
  dt_camera_t *cam=(dt_camera_t *)camera;
  dt_pthread_mutex_lock(&cam->config_lock);
  CameraWidget *remote; // Copy of remote configuration
  gp_camera_get_config( camera->gpcam, &remote, c->gpcontext );
  // merge remote copy with cache and notify on changed properties to host application
  _camera_configuration_merge(c, camera, remote, camera->configuration, FALSE );
  dt_pthread_mutex_unlock(&cam->config_lock);
}
Beispiel #8
0
static int32_t dt_control_run_job(dt_control_t *control)
{
  _dt_job_t *job = dt_control_schedule_job(control);

  if(!job) return -1;

  /* change state to running */
  dt_pthread_mutex_lock(&job->wait_mutex);
  if(dt_control_job_get_state(job) == DT_JOB_STATE_QUEUED)
  {
    dt_print(DT_DEBUG_CONTROL, "[run_job+] %02d %f ", DT_CTL_WORKER_RESERVED + dt_control_get_threadid(),
             dt_get_wtime());
    dt_control_job_print(job);
    dt_print(DT_DEBUG_CONTROL, "\n");

    dt_control_job_set_state(job, DT_JOB_STATE_RUNNING);

    /* execute job */
    job->result = job->execute(job);

    dt_control_job_set_state(job, DT_JOB_STATE_FINISHED);

    dt_print(DT_DEBUG_CONTROL, "[run_job-] %02d %f ", DT_CTL_WORKER_RESERVED + dt_control_get_threadid(),
             dt_get_wtime());
    dt_control_job_print(job);
    dt_print(DT_DEBUG_CONTROL, "\n");
  }

  dt_pthread_mutex_unlock(&job->wait_mutex);

  // remove the job from scheduled job array (for job deduping)
  dt_pthread_mutex_lock(&control->queue_mutex);
  control->job[dt_control_get_threadid()] = NULL;
  if(job->queue == DT_JOB_QUEUE_USER_EXPORT) control->export_scheduled = FALSE;
  dt_pthread_mutex_unlock(&control->queue_mutex);

  // and free it
  dt_control_job_dispose(job);

  return 0;
}
Beispiel #9
0
void dt_control_job_wait(dt_job_t *j)
{
  int state = dt_control_job_get_state (j);

  /* if job execution not is finished let's wait for signal */
  if (state==DT_JOB_STATE_RUNNING || state==DT_JOB_STATE_CANCELLED)
  {
    dt_pthread_mutex_lock (&j->wait_mutex);
    dt_pthread_mutex_unlock (&j->wait_mutex);
  }

}
Beispiel #10
0
void dt_control_job_wait(_dt_job_t *job)
{
  if(!job) return;
  dt_job_state_t state = dt_control_job_get_state(job);

  /* if job execution is not finished let's wait for signal */
  if(state == DT_JOB_STATE_RUNNING || state == DT_JOB_STATE_CANCELLED)
  {
    dt_pthread_mutex_lock(&job->wait_mutex);
    dt_pthread_mutex_unlock(&job->wait_mutex);
  }
}
Beispiel #11
0
static void *dt_control_worker_kicker(void *ptr)
{
  dt_control_t *control = (dt_control_t *)ptr;
  while(dt_control_running())
  {
    sleep(2);
    dt_pthread_mutex_lock(&control->cond_mutex);
    pthread_cond_broadcast(&control->cond);
    dt_pthread_mutex_unlock(&control->cond_mutex);
  }
  return NULL;
}
Beispiel #12
0
void dt_control_shutdown(dt_control_t *s)
{
  dt_pthread_mutex_lock(&s->cond_mutex);
  dt_pthread_mutex_lock(&s->run_mutex);
  s->running = 0;
  dt_pthread_mutex_unlock(&s->run_mutex);
  dt_pthread_mutex_unlock(&s->cond_mutex);
  pthread_cond_broadcast(&s->cond);

  /* first wait for kick_on_workers_thread */
  pthread_join(s->kick_on_workers_thread, NULL);

  int k;
  for(k = 0; k < s->num_threads; k++)
    // pthread_kill(s->thread[k], 9);
    pthread_join(s->thread[k], NULL);
  for(k = 0; k < DT_CTL_WORKER_RESERVED; k++)
    // pthread_kill(s->thread_res[k], 9);
    pthread_join(s->thread_res[k], NULL);

}
Beispiel #13
0
void dt_control_set_mouse_over_id(int32_t value)
{
  dt_pthread_mutex_lock(&(darktable.control->global_mutex));
  if(darktable.control->mouse_over_id != value)
  {
    darktable.control->mouse_over_id = value;
    dt_pthread_mutex_unlock(&(darktable.control->global_mutex));
    dt_control_signal_raise(darktable.signals, DT_SIGNAL_MOUSE_OVER_IMAGE_CHANGE);
  }
  else
    dt_pthread_mutex_unlock(&(darktable.control->global_mutex));
}
Beispiel #14
0
int dt_cache_remove(dt_cache_t *cache, const uint32_t key)
{
  gpointer orig_key, value;
  gboolean res;
  int result;
  dt_cache_entry_t *entry;
restart:
  dt_pthread_mutex_lock(&cache->lock);

  res = g_hash_table_lookup_extended(
      cache->hashtable, GINT_TO_POINTER(key), &orig_key, &value);
  entry = (dt_cache_entry_t *)value;
  if(!res)
  { // not found in cache, not deleting.
    dt_pthread_mutex_unlock(&cache->lock);
    return 1;
  }
  // need write lock to be able to delete:
  result = dt_pthread_rwlock_trywrlock(&entry->lock);
  if(result)
  {
    dt_pthread_mutex_unlock(&cache->lock);
    g_usleep(5);
    goto restart;
  }

  if(entry->_lock_demoting)
  {
    // oops, we are currently demoting (rw -> r) lock to this entry in some thread. do not touch!
    dt_pthread_rwlock_unlock(&entry->lock);
    dt_pthread_mutex_unlock(&cache->lock);
    g_usleep(5);
    goto restart;
  }

  gboolean removed = g_hash_table_remove(cache->hashtable, GINT_TO_POINTER(key));
  (void)removed; // make non-assert compile happy
  assert(removed);
  cache->lru = g_list_delete_link(cache->lru, entry->link);

  if(cache->cleanup)
    cache->cleanup(cache->cleanup_data, entry);
  else
    dt_free_align(entry->data);
  dt_pthread_rwlock_unlock(&entry->lock);
  dt_pthread_rwlock_destroy(&entry->lock);
  cache->cost -= entry->cost;
  g_slice_free1(sizeof(*entry), entry);

  dt_pthread_mutex_unlock(&cache->lock);
  return 0;
}
Beispiel #15
0
gboolean dt_lua_lock()
{
  gboolean had_lock = dt_control_gdk_haslock();
  if(had_lock){
    dt_control_gdk_unlock();
  }
  if(!darktable.lua_state.ending && pthread_equal(darktable.control->gui_thread,pthread_self()) != 0) {
    dt_print(DT_DEBUG_LUA,"LUA WARNING locking from the gui thread should be avoided\n");
  }

  dt_pthread_mutex_lock(&darktable.lua_state.mutex);
  return had_lock;
}
Beispiel #16
0
gpointer _camera_get_job( const dt_camctl_t *c,const dt_camera_t *camera )
{
  dt_camera_t *cam=(dt_camera_t *)camera;
  dt_pthread_mutex_lock(&cam->jobqueue_lock);
  gpointer job=NULL;
  if(  g_list_length(cam->jobqueue) > 0 )
  {
    job = g_list_nth_data(cam->jobqueue,0);
    cam->jobqueue = g_list_remove(cam->jobqueue,job);
  }
  dt_pthread_mutex_unlock(&cam->jobqueue_lock);
  return job;
}
Beispiel #17
0
void dt_lua_lock_internal(const char *function, const char *file, int line, gboolean silent)
{
  if(!silent && !darktable.lua_state.ending && pthread_equal(darktable.control->gui_thread, pthread_self()) != 0)
  {
    dt_print(DT_DEBUG_LUA, "LUA WARNING locking from the gui thread should be avoided\n");
    //g_assert(false);
  }

  dt_pthread_mutex_lock(&darktable.lua_state.mutex);
#ifdef _DEBUG
  dt_print(DT_DEBUG_LUA,"LUA DEBUG : %s called from %s:%d (%s)\n", __FUNCTION__, file, line, function);
#endif
}
Beispiel #18
0
void _camera_configuration_commit(const dt_camctl_t *c,const dt_camera_t *camera)
{
  g_assert( camera != NULL );

  dt_camera_t *cam=(dt_camera_t *)camera;

  dt_pthread_mutex_lock(&cam->config_lock);
  if( gp_camera_set_config( camera->gpcam, camera->configuration, c->gpcontext) != GP_OK )
    dt_print(DT_DEBUG_CAMCTL,"[camera_control] Failed to commit configuration changes to camera\n");

  cam->config_changed=FALSE;
  dt_pthread_mutex_unlock(&cam->config_lock);
}
Beispiel #19
0
void dt_opencl_free_kernel(const int kernel)
{
  dt_opencl_t *cl = darktable.opencl;
  if(!cl->inited) return;
  if(kernel < 0 || kernel >= DT_OPENCL_MAX_KERNELS) return;
  dt_pthread_mutex_lock(&cl->lock);
  for(int dev=0; dev<cl->num_devs; dev++)
  {
    cl->dev[dev].kernel_used [kernel] = 0;
    (cl->dlocl->symbols->dt_clReleaseKernel) (cl->dev[dev].kernel [kernel]);
  }
  dt_pthread_mutex_unlock(&cl->lock);
}
Beispiel #20
0
void dt_camctl_register_listener( const dt_camctl_t *c, dt_camctl_listener_t *listener)
{
  dt_camctl_t *camctl=(dt_camctl_t *)c;
  // Just locking mutex and prevent signalling CAMERA_CONTROL_BUSY
  dt_pthread_mutex_lock(&camctl->lock);
  if( g_list_find(camctl->listeners,listener) == NULL )
  {
    camctl->listeners=g_list_append(camctl->listeners,listener);
    dt_print(DT_DEBUG_CAMCTL,"[camera_control] registering listener %lx\n",(unsigned long int)listener);
  }
  else
    dt_print(DT_DEBUG_CAMCTL,"[camera_control] registering already registered listener %lx\n",(unsigned long int)listener);
  dt_pthread_mutex_unlock(&camctl->lock);
}
Beispiel #21
0
void dt_control_gdk_unlock()
{
  /* check if current thread has a lock and remove if exists */
  dt_pthread_mutex_lock(&_control_gdk_lock_threads_mutex);
  if(_control_gdk_lock_mine)
  {
    /* remove lock */
    _control_gdk_lock_mine = FALSE;

    /* leave critical section */
    gdk_threads_leave();
  }
  dt_pthread_mutex_unlock(&_control_gdk_lock_threads_mutex);
}
Beispiel #22
0
int32_t dt_film_import1_run(dt_job_t *job)
{
  dt_film_import1_t *t = (dt_film_import1_t *)job->param;
  dt_film_import1(t->film);
  dt_pthread_mutex_lock(&t->film->images_mutex);
  t->film->ref--;
  dt_pthread_mutex_unlock(&t->film->images_mutex);
  if(t->film->ref <= 0)
  {
    dt_film_cleanup(t->film);
    free(t->film);
  }
  return 0;
}
Beispiel #23
0
static void dt_control_job_set_state(_dt_job_t *job, dt_job_state_t state)
{
  if(!job) return;
  dt_pthread_mutex_lock(&job->state_mutex);
  if(state >= DT_JOB_STATE_FINISHED  && job->state != DT_JOB_STATE_RUNNING && job->progress)
  {
    dt_control_progress_destroy(darktable.control, job->progress);
    job->progress = NULL;
  }
  job->state = state;
  /* pass state change to callback */
  if(job->state_changed_cb) job->state_changed_cb(job, state);
  dt_pthread_mutex_unlock(&job->state_mutex);
}
Beispiel #24
0
static int32_t dt_control_run_job_res(dt_control_t *control, int32_t res)
{
  if(((unsigned int)res) >= DT_CTL_WORKER_RESERVED) return -1;

  _dt_job_t *job = NULL;
  dt_pthread_mutex_lock(&control->queue_mutex);
  if(control->new_res[res])
  {
    job = control->job_res[res];
    control->job_res[res] = NULL; // this job belongs to us now, the queue may not touch it any longer
  }
  control->new_res[res] = 0;
  dt_pthread_mutex_unlock(&control->queue_mutex);
  if(!job) return -1;

  /* change state to running */
  dt_pthread_mutex_lock(&job->wait_mutex);
  if(dt_control_job_get_state(job) == DT_JOB_STATE_QUEUED)
  {
    dt_print(DT_DEBUG_CONTROL, "[run_job+] %02d %f ", res, dt_get_wtime());
    dt_control_job_print(job);
    dt_print(DT_DEBUG_CONTROL, "\n");

    dt_control_job_set_state(job, DT_JOB_STATE_RUNNING);

    /* execute job */
    job->result = job->execute(job);

    dt_control_job_set_state(job, DT_JOB_STATE_FINISHED);
    dt_print(DT_DEBUG_CONTROL, "[run_job-] %02d %f ", res, dt_get_wtime());
    dt_control_job_print(job);
    dt_print(DT_DEBUG_CONTROL, "\n");
  }
  dt_pthread_mutex_unlock(&job->wait_mutex);
  dt_control_job_dispose(job);
  return 0;
}
Beispiel #25
0
int dt_film_new(dt_film_t *film, const char *directory)
{
  // Try open filmroll for folder if exists
  film->id = -1;
  int rc;
  sqlite3_stmt *stmt;
  DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
                              "select id from film_rolls where folder = ?1", -1, &stmt, NULL);
  DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 1, directory, strlen(directory),
                             SQLITE_STATIC);
  if(sqlite3_step(stmt) == SQLITE_ROW)
    film->id = sqlite3_column_int(stmt, 0);
  sqlite3_finalize(stmt);

  if(film->id <= 0)
  {
    // create a new filmroll
    sqlite3_stmt *stmt;
    char datetime[20];
    dt_gettime(datetime);
    DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
                                "insert into film_rolls (id, datetime_accessed, folder) "
                                "values (null, ?1, ?2)", -1, &stmt, NULL);
    DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 1, datetime, strlen(datetime),
                               SQLITE_STATIC);
    DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 2, directory, strlen(directory),
                               SQLITE_STATIC);
    dt_pthread_mutex_lock(&darktable.db_insert);
    rc = sqlite3_step(stmt);
    if(rc != SQLITE_DONE)
      fprintf(stderr, "[film_new] failed to insert film roll! %s\n",
              sqlite3_errmsg(dt_database_get(darktable.db)));
    sqlite3_finalize(stmt);
    DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
                                "select id from film_rolls where folder=?1", -1, &stmt, NULL);
    DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 1, directory, strlen(directory),
                               SQLITE_STATIC);
    if(sqlite3_step(stmt) == SQLITE_ROW)
      film->id = sqlite3_column_int(stmt, 0);
    sqlite3_finalize(stmt);
    dt_pthread_mutex_unlock(&darktable.db_insert);
  }

  if(film->id<=0)
    return 0;
  g_strlcpy(film->dirname,directory,sizeof(film->dirname));
  film->last_loaded = 0;
  return film->id;
}
Beispiel #26
0
static int32_t dt_control_run_job(dt_control_t *control)
{
  _dt_job_t *job = dt_control_schedule_job(control);

  if(!job) return -1;

  /* change state to running */
  dt_pthread_mutex_lock(&job->wait_mutex);
  if(dt_control_job_get_state(job) == DT_JOB_STATE_QUEUED)
    dt_control_job_execute(job);

  dt_pthread_mutex_unlock(&job->wait_mutex);

  // remove the job from scheduled job array (for job deduping)
  dt_pthread_mutex_lock(&control->queue_mutex);
  control->job[dt_control_get_threadid()] = NULL;
  if(job->queue == DT_JOB_QUEUE_USER_EXPORT) control->export_scheduled = FALSE;
  dt_pthread_mutex_unlock(&control->queue_mutex);

  // and free it
  dt_control_job_dispose(job);

  return 0;
}
Beispiel #27
0
void dt_control_log(const char *msg, ...)
{
  dt_pthread_mutex_lock(&darktable.control->log_mutex);
  va_list ap;
  va_start(ap, msg);
  vsnprintf(darktable.control->log_message[darktable.control->log_pos], DT_CTL_LOG_MSG_SIZE, msg, ap);
  va_end(ap);
  if(darktable.control->log_message_timeout_id) g_source_remove(darktable.control->log_message_timeout_id);
  darktable.control->log_ack = darktable.control->log_pos;
  darktable.control->log_pos = (darktable.control->log_pos + 1) % DT_CTL_LOG_SIZE;
  darktable.control->log_message_timeout_id
      = g_timeout_add(DT_CTL_LOG_TIMEOUT, _dt_ctl_log_message_timeout_callback, NULL);
  dt_pthread_mutex_unlock(&darktable.control->log_mutex);
  dt_control_queue_redraw_center();
}
Beispiel #28
0
void dt_control_progress_cancel(dt_control_t *control, dt_progress_t *progress)
{
  dt_pthread_mutex_lock(&progress->mutex);
  if(progress->cancel == NULL)
  {
    dt_pthread_mutex_unlock(&progress->mutex);
    return;
  }

  // call the cancel callback
  progress->cancel(progress, progress->cancel_data);

  dt_pthread_mutex_unlock(&progress->mutex);

  // the gui doesn't need to know I guess, it wouldn't to anything with that bit of information
}
Beispiel #29
0
static int32_t dt_film_import1_run(dt_job_t *job)
{
  dt_film_import1_t *params = dt_control_job_get_params(job);
  dt_film_import1(job, params->film);
  dt_pthread_mutex_lock(&params->film->images_mutex);
  params->film->ref--;
  dt_pthread_mutex_unlock(&params->film->images_mutex);
  if(params->film->ref <= 0)
  {
    if(dt_film_is_empty(params->film->id))
    {
      dt_film_remove(params->film->id);
    }
  }
  return 0;
}
Beispiel #30
0
static void _lib_history_change_callback(gpointer instance, gpointer user_data)
{
  dt_lib_module_t *self = (dt_lib_module_t *)user_data;
  dt_lib_history_t *d = (dt_lib_history_t *)self->data;

  /* first destroy all buttons in list */
  gtk_container_foreach(GTK_CONTAINER(d->history_box), (GtkCallback)gtk_widget_destroy, 0);

  /* add default which always should be */
  int num = -1;
  gtk_box_pack_start(GTK_BOX(d->history_box),
                     _lib_history_create_button(self, num, _("original"), FALSE, darktable.develop->history_end == 0),
                     TRUE, TRUE, 0);
  num++;

  /* lock history mutex */
  dt_pthread_mutex_lock(&darktable.develop->history_mutex);

  /* iterate over history items and add them to list*/
  GList *history = g_list_first(darktable.develop->history);
  while(history)
  {
    dt_dev_history_item_t *hitem = (dt_dev_history_item_t *)(history->data);

    gchar *label;
    if(!hitem->multi_name[0] || strcmp(hitem->multi_name, "0") == 0)
      label = g_strdup_printf("%s", hitem->module->name());
    else
      label = g_strdup_printf("%s %s", hitem->module->name(), hitem->multi_name);

    gboolean selected = (num == darktable.develop->history_end - 1);
    GtkWidget *widget = _lib_history_create_button(self, num, label, hitem->enabled, selected);
    g_free(label);

    gtk_box_pack_start(GTK_BOX(d->history_box), widget, TRUE, TRUE, 0);
    gtk_box_reorder_child(GTK_BOX(d->history_box), widget, 0);
    num++;

    history = g_list_next(history);
  }

  /* show all widgets */
  gtk_widget_show_all(d->history_box);

  dt_pthread_mutex_unlock(&darktable.develop->history_mutex);
}