예제 #1
0
static int lua_job_progress(lua_State *L)
{
    dt_progress_t *progress;
    luaA_to(L, dt_lua_backgroundjob_t, &progress, 1);
    dt_lua_unlock(false);
    gboolean i_own_lock = dt_control_gdk_lock();
    dt_pthread_mutex_lock(&darktable.control->progress_system.mutex);
    GList *iter = g_list_find(darktable.control->progress_system.list, progress);
    dt_pthread_mutex_unlock(&darktable.control->progress_system.mutex);
    if(i_own_lock) dt_control_gdk_unlock();
    dt_lua_lock();
    if(!iter) luaL_error(L,"Accessing an invalid job");
    if(lua_isnone(L, 3))
    {
        dt_lua_unlock(false);
        double result = dt_control_progress_get_progress(progress);
        dt_lua_lock();
        if(!dt_control_progress_has_progress_bar(progress))
            lua_pushnil(L);
        else
            lua_pushnumber(L, result);
        return 1;
    }
    else
    {
        double value;
        luaA_to(L,progress_double,&value,3);
        dt_lua_unlock(false);
        dt_control_progress_set_progress(darktable.control, progress, value);
        dt_lua_lock();
        return 0;
    }
}
예제 #2
0
void dt_ctl_switch_mode_to(dt_control_gui_mode_t mode)
{
  dt_control_gui_mode_t oldmode = dt_conf_get_int("ui_last/view");
  if(oldmode == mode) return;

  darktable.control->button_down = 0;
  darktable.control->button_down_which = 0;
  darktable.gui->center_tooltip = 0;
  GtkWidget *widget = dt_ui_center(darktable.gui->ui);
  g_object_set(G_OBJECT(widget), "tooltip-text", "", (char *)NULL);

  char buf[512];
  snprintf(buf, sizeof(buf) - 1, _("switch to %s mode"),
           dt_view_manager_name(darktable.view_manager));

  gboolean i_own_lock = dt_control_gdk_lock();

  int error = dt_view_manager_switch(darktable.view_manager, mode);

  if(i_own_lock) dt_control_gdk_unlock();

  if(error) return;

  dt_conf_set_int ("ui_last/view", mode);
}
예제 #3
0
static int lua_job_valid(lua_State*L)
{
    dt_progress_t *progress;
    luaA_to(L, dt_lua_backgroundjob_t, &progress, 1);
    if(lua_isnone(L, 3))
    {
        dt_lua_unlock(false);
        gboolean i_own_lock = dt_control_gdk_lock();
        dt_pthread_mutex_lock(&darktable.control->progress_system.mutex);
        GList *iter = g_list_find(darktable.control->progress_system.list, progress);
        dt_pthread_mutex_unlock(&darktable.control->progress_system.mutex);
        if(i_own_lock) dt_control_gdk_unlock();
        dt_lua_lock();

        if(iter)
            lua_pushboolean(L, true);
        else
            lua_pushboolean(L, false);

        return 1;
    }
    else
    {
        int validity = lua_toboolean(L, 3);
        if(validity)
            return luaL_argerror(L, 3, "a job can not be made valid");
        dt_lua_unlock(false);
        dt_control_progress_destroy(darktable.control, progress);
        dt_lua_lock();
        return 0;
    }
}
예제 #4
0
static void _lib_filmstrip_scroll_to_image(dt_lib_module_t *self, gint imgid, gboolean activate)
{
  dt_lib_filmstrip_t *strip = (dt_lib_filmstrip_t *)self->data;

  /* if no imgid just bail out */
  if(imgid <= 0) return;

  strip->activated_image = imgid;

  strip->offset = dt_collection_image_offset(imgid);

  DT_CTL_SET_GLOBAL(lib_image_mouse_over_id, strip->activated_image);

  /* activate the image if requested */
  if (activate)
  {
    strip->activated_image = imgid;
    dt_control_signal_raise(darktable.signals, DT_SIGNAL_VIEWMANAGER_FILMSTRIP_ACTIVATE);
  }

  /* redraw filmstrip */
  gboolean owns_lock = dt_control_gdk_lock();
  gtk_widget_queue_draw(self->widget);
  if(owns_lock) dt_control_gdk_unlock();
}
예제 #5
0
static void _lib_backgroundjobs_destroy(dt_lib_module_t *self, const guint *key)
{
  dt_lib_backgroundjobs_t *d = (dt_lib_backgroundjobs_t*)self->data;

  gboolean i_own_lock = dt_control_gdk_lock();

  dt_bgjob_t *j = (dt_bgjob_t*)g_hash_table_lookup(d->jobs, key);
  if(j)
  {
    g_hash_table_remove(d->jobs, key);

    /* remove job widget from jobbox */
    if(GTK_IS_WIDGET(j->widget))
      gtk_container_remove(GTK_CONTAINER(d->jobbox),j->widget);

    /* if jobbox is empty lets hide */
    if(g_list_length(gtk_container_get_children(GTK_CONTAINER(d->jobbox)))==0)
      gtk_widget_hide(d->jobbox);

    /* free allocted mem */
    g_free(j);
    g_free((guint*)key);
  }
  if(i_own_lock) dt_control_gdk_unlock();
}
예제 #6
0
void dt_control_queue_redraw_widget(GtkWidget *widget)
{
  if(dt_control_running())
  {
    gboolean i_own_lock = dt_control_gdk_lock();

    gtk_widget_queue_draw(widget);

    if (i_own_lock) dt_control_gdk_unlock();
  }
}
예제 #7
0
파일: signal.c 프로젝트: bleader/darktable
void dt_control_signal_raise(const dt_control_signal_t *ctlsig, dt_signal_t signal,...)
{
  va_list extra_args;
  // ignore all signals on shutdown, especially don't lock anything..
  if(!dt_control_running()) return;
  va_start(extra_args,signal);
  gboolean i_own_lock = dt_control_gdk_lock();
  //g_signal_emit_by_name(G_OBJECT(ctlsig->sink), _signal_description[signal].name);
  g_signal_emit_valist(G_OBJECT(ctlsig->sink),g_signal_lookup(_signal_description[signal].name,_signal_type), 0,extra_args);
  va_end(extra_args);
  if (i_own_lock) dt_control_gdk_unlock();
}
예제 #8
0
static const guint * _lib_backgroundjobs_create(dt_lib_module_t *self,int type,const gchar *message)
{
  dt_lib_backgroundjobs_t *d = (dt_lib_backgroundjobs_t *)self->data;

  /* lets make this threadsafe */
  gboolean i_own_lock = dt_control_gdk_lock();

  /* initialize a new job */
  dt_bgjob_t *j=(dt_bgjob_t*)g_malloc(sizeof(dt_bgjob_t));
  j->type = type;
  j->widget = gtk_event_box_new();

  guint *key = g_malloc(sizeof(guint));
  *key = g_direct_hash((gconstpointer)j);

  /* create in hash out of j pointer*/
  g_hash_table_insert(d->jobs, key, j);

  /* intialize the ui elements for job */
  gtk_widget_set_name (GTK_WIDGET (j->widget), "background_job_eventbox");
  GtkBox *vbox = GTK_BOX (gtk_vbox_new (FALSE,0));
  GtkBox *hbox = GTK_BOX (gtk_hbox_new (FALSE,0));
  gtk_container_set_border_width (GTK_CONTAINER(vbox),2);
  gtk_container_add (GTK_CONTAINER(j->widget), GTK_WIDGET(vbox));

  /* add job label */
  j->label = gtk_label_new(message);
  gtk_misc_set_alignment(GTK_MISC(j->label), 0.0, 0.5);
  gtk_box_pack_start( GTK_BOX( hbox ), GTK_WIDGET(j->label), TRUE, TRUE, 0);
  gtk_box_pack_start( GTK_BOX( vbox ), GTK_WIDGET(hbox), TRUE, TRUE, 0);

  /* use progressbar ? */
  if (type == 0)
  {
    j->progressbar = gtk_progress_bar_new();
    gtk_box_pack_start( GTK_BOX( vbox ), j->progressbar, TRUE, FALSE, 2);

#ifdef HAVE_UNITY
    j->darktable_launcher = unity_launcher_entry_get_for_desktop_id("darktable.desktop");
    unity_launcher_entry_set_progress( j->darktable_launcher, 0.0 );
    unity_launcher_entry_set_progress_visible( j->darktable_launcher, TRUE );
#endif
  }

  /* lets show jobbox if its hidden */
  gtk_box_pack_start(GTK_BOX(d->jobbox), j->widget, TRUE, FALSE, 1);
  gtk_box_reorder_child(GTK_BOX(d->jobbox), j->widget, 1);
  gtk_widget_show_all(j->widget);
  gtk_widget_show(d->jobbox);

  if(i_own_lock) dt_control_gdk_unlock();
  return key;
}
예제 #9
0
파일: import.c 프로젝트: ealasu/darktable
/** camctl camera disconnect callback */
static void _camctl_camera_disconnected_callback (const dt_camera_t *camera,void *data)
{
  dt_lib_module_t *self = (dt_lib_module_t *)data;


  /* rescan connected cameras */
  dt_camctl_detect_cameras(darktable.camctl);

  /* update gui with detected devices */
  gboolean i_own_lock = dt_control_gdk_lock();
  _lib_import_ui_devices_update(self);
  if(i_own_lock) dt_control_gdk_unlock();
}
예제 #10
0
파일: lua.c 프로젝트: bartokk/darktable
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;
}
예제 #11
0
static gboolean _slider_postponed_value_change(gpointer data)
{
  gboolean i_own_lock = dt_control_gdk_lock();

  if (DTGTK_SLIDER(data)->is_changed==TRUE)
  {
    g_signal_emit_by_name(G_OBJECT(data),"value-changed");
    if(DTGTK_SLIDER(data)->type==DARKTABLE_SLIDER_VALUE)
      DTGTK_SLIDER(data)->is_changed=FALSE;
  }

  if (i_own_lock) dt_control_gdk_unlock();

  return DTGTK_SLIDER(data)->is_dragging;	// This is called by the gtk mainloop and is threadsafe
}
예제 #12
0
static void _lib_backgroundjobs_progress(dt_lib_module_t *self, const guint *key, double progress)
{
  if(!darktable.control->running) return;
  dt_lib_backgroundjobs_t *d = (dt_lib_backgroundjobs_t*)self->data;
  gboolean i_own_lock = dt_control_gdk_lock();

  dt_bgjob_t *j = (dt_bgjob_t*)g_hash_table_lookup(d->jobs, key);
  if(j)
  {
    /* check if progress is above 1.0 and destroy bgjob if finished */
    /* FIXME: actually we are having some rounding issues, where the */
    /* FIXME: last item doesn't bring to total to 1.0 flat */
    /* FIXME: so this is why we have the ugly kludge below */
    if (progress > 0.999999)
    {
      if (GTK_IS_WIDGET(j->widget))
        gtk_container_remove( GTK_CONTAINER(d->jobbox), j->widget );

#ifdef HAVE_UNITY
      unity_launcher_entry_set_progress( j->darktable_launcher, 1.0 );
      unity_launcher_entry_set_progress_visible( j->darktable_launcher, FALSE );
#endif
#ifdef MAC_INTEGRATION
#ifdef GTK_TYPE_OSX_APPLICATION
      gtk_osxapplication_attention_request(g_object_new(GTK_TYPE_OSX_APPLICATION, NULL), INFO_REQUEST);
#else
      gtkosx_application_attention_request(g_object_new(GTKOSX_TYPE_APPLICATION, NULL), INFO_REQUEST);
#endif
#endif

      /* hide jobbox if theres no jobs left */
      if (g_list_length(gtk_container_get_children(GTK_CONTAINER(d->jobbox))) == 0 )
        gtk_widget_hide(d->jobbox);
    }
    else
    {
      if( j->type == 0 )
        gtk_progress_bar_set_fraction( GTK_PROGRESS_BAR(j->progressbar), progress );

#ifdef HAVE_UNITY
      unity_launcher_entry_set_progress( j->darktable_launcher, progress );
#endif
    }
  }

  if(i_own_lock) dt_control_gdk_unlock();
}
예제 #13
0
static void _lib_backgroundjobs_progress(dt_lib_module_t *self, const guint *key, double progress)
{
  if(!darktable.control->running) return;
  gboolean i_own_lock = dt_control_gdk_lock();
  dt_lib_backgroundjobs_t *d = (dt_lib_backgroundjobs_t*)self->data;

  dt_bgjob_t *j = (dt_bgjob_t*)g_hash_table_lookup(d->jobs, key);
  if(j)
  {
    if( j->type == 0 )
      gtk_progress_bar_set_fraction( GTK_PROGRESS_BAR(j->progressbar), progress );

#ifdef HAVE_UNITY
    unity_launcher_entry_set_progress( j->darktable_launcher, progress );
#endif
  }

  if(i_own_lock) dt_control_gdk_unlock();
}
예제 #14
0
파일: import.c 프로젝트: ealasu/darktable
/** camctl status listener callback */
static void _camctl_camera_control_status_callback(dt_camctl_status_t status,void *data)
{
  dt_lib_module_t *self = (dt_lib_module_t *)data;
  dt_lib_import_t *d = (dt_lib_import_t*)self->data;

  /* check if we need gdk locking */
  gboolean i_have_lock = dt_control_gdk_lock();

  /* handle camctl status */
  switch(status)
  {
    case CAMERA_CONTROL_BUSY:
    {
      /* set all devicese as inaccessible */
      GList *child = gtk_container_get_children(GTK_CONTAINER(d->devices));
      if(child)
        do
        {
          if( !(GTK_IS_TOGGLE_BUTTON(child->data)  && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(child->data))==TRUE) )
            gtk_widget_set_sensitive(GTK_WIDGET(child->data),FALSE);
        }
        while( (child=g_list_next(child)) );
    }
    break;

    case CAMERA_CONTROL_AVAILABLE:
    {
      /* set all devices as accessible */
      GList *child = gtk_container_get_children(GTK_CONTAINER(d->devices));
      if(child)
        do
        {
          gtk_widget_set_sensitive(GTK_WIDGET(child->data),TRUE);
        }
        while( (child=g_list_next(child)) );
    }
    break;
  }

  /* unlock */
  if(i_have_lock) dt_control_gdk_unlock();
}
예제 #15
0
static void _lib_modulegroups_set(dt_lib_module_t *self, uint32_t group)
{
  dt_lib_modulegroups_t *d = (dt_lib_modulegroups_t *)self->data;

  /* this is a proxy function so it might be called from another thread */
  gboolean i_own_lock = dt_control_gdk_lock();

  /* if no change just update visibility */
  if(d->current == group)
  {
    _lib_modulegroups_update_iop_visibility(self);
    return;
  }

  /* set current group */
  if(group < DT_MODULEGROUP_SIZE && GTK_IS_TOGGLE_BUTTON(d->buttons[group]))
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(d->buttons[group]), TRUE);

  if(i_own_lock) dt_control_gdk_unlock();
}
예제 #16
0
static void _lib_backgroundjobs_destroy(dt_lib_module_t *self, const guint *key)
{
  gboolean i_own_lock = dt_control_gdk_lock();

  dt_lib_backgroundjobs_t *d = (dt_lib_backgroundjobs_t*)self->data;

  dt_bgjob_t *j = (dt_bgjob_t*)g_hash_table_lookup(d->jobs, key);
  if(j)
  {
    g_hash_table_remove(d->jobs, key);

    /* remove job widget from jobbox */
    if(j->widget && GTK_IS_WIDGET(j->widget))
      gtk_container_remove(GTK_CONTAINER(d->jobbox),j->widget);
    j->widget = 0;

#ifdef HAVE_UNITY
    if( j->type == 0 )
    {
      unity_launcher_entry_set_progress( j->darktable_launcher, 1.0 );
      unity_launcher_entry_set_progress_visible( j->darktable_launcher, FALSE );
    }
#endif
#ifdef MAC_INTEGRATION
#ifdef GTK_TYPE_OSX_APPLICATION
    gtk_osxapplication_attention_request(g_object_new(GTK_TYPE_OSX_APPLICATION, NULL), INFO_REQUEST);
#else
    gtkosx_application_attention_request(g_object_new(GTKOSX_TYPE_APPLICATION, NULL), INFO_REQUEST);
#endif
#endif

    /* if jobbox is empty lets hide */
    if(g_list_length(gtk_container_get_children(GTK_CONTAINER(d->jobbox)))==0)
      gtk_widget_hide(d->jobbox);

    /* free allocted mem */
    g_free(j);
    g_free((guint*)key);
  }
  if(i_own_lock) dt_control_gdk_unlock();
}
예제 #17
0
static void _lib_backgroundjobs_set_cancellable(dt_lib_module_t *self, const guint *key, struct dt_job_t *job)
{
  if(!darktable.control->running) return;
  gboolean i_own_lock = dt_control_gdk_lock();

  dt_lib_backgroundjobs_t *d = (dt_lib_backgroundjobs_t*)self->data;

  dt_bgjob_t *j = (dt_bgjob_t*)g_hash_table_lookup(d->jobs, key);
  if (j)
  {
    GtkWidget *w=j->widget;
    GtkBox *hbox = GTK_BOX (g_list_nth_data (gtk_container_get_children (GTK_CONTAINER ( gtk_bin_get_child (GTK_BIN (w) ) ) ), 0));
    GtkWidget *button = dtgtk_button_new(dtgtk_cairo_paint_cancel,CPF_STYLE_FLAT);
    gtk_widget_set_size_request(button,17,17);
    g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (_lib_backgroundjobs_cancel_callback), (gpointer)job);
    gtk_box_pack_start (hbox, GTK_WIDGET(button), FALSE, FALSE, 0);
    gtk_widget_show_all(button);
  }

  if(i_own_lock) dt_control_gdk_unlock();
}
예제 #18
0
static void _lib_filmstrip_scroll_to_image(dt_lib_module_t *self, gint imgid, gboolean activate)
{
  dt_lib_filmstrip_t *strip = (dt_lib_filmstrip_t *)self->data;
 
  /* if no imgid just bail out */
  if(imgid <= 0) return;

  strip->activated_image = imgid;

  char query[1024];
  const gchar *qin = dt_collection_get_query (darktable.collection);
  if(qin)
  {
    snprintf(query, 1024, "select rowid from (%s) where id=?3", qin);
    sqlite3_stmt *stmt;
    DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), query, -1, &stmt, NULL);
    DT_DEBUG_SQLITE3_BIND_INT(stmt, 1,  0);
    DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, -1);
    DT_DEBUG_SQLITE3_BIND_INT(stmt, 3, imgid);
    if(sqlite3_step(stmt) == SQLITE_ROW)
    {
      strip->offset = sqlite3_column_int(stmt, 0) - 1;
    }
    sqlite3_finalize(stmt);
  }

  /* activate the image if requested */
  if (activate)
  {
    strip->activated_image = imgid;
    dt_control_signal_raise(darktable.signals, DT_SIGNAL_VIEWMANAGER_FILMSTRIP_ACTIVATE);
  }

  /* redraw filmstrip */
  gboolean owns_lock = dt_control_gdk_lock();
  gtk_widget_queue_draw(self->widget);
  if(owns_lock) dt_control_gdk_unlock();
}
예제 #19
0
/* Detect hot sensor pixels based on the 4 surrounding sites. Pixels
 * having 3 or 4 (depending on permissive setting) surrounding pixels that
 * than value*multiplier are considered "hot", and are replaced by the maximum of
 * the neighbour pixels. The permissive variant allows for
 * correcting pairs of hot pixels in adjacent sites. Replacement using
 * the maximum produces fewer artifacts when inadvertently replacing
 * non-hot pixels. */
void process (struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, void *i, void *o, const dt_iop_roi_t *roi_in, const dt_iop_roi_t *roi_out)
{
  dt_iop_hotpixels_gui_data_t *g = (dt_iop_hotpixels_gui_data_t *)self->gui_data;
  const dt_iop_hotpixels_data_t *data = (dt_iop_hotpixels_data_t *)piece->data;
  const float threshold = data->threshold;
  const float multiplier = data->multiplier;
  const int width = roi_out->width;
  const int widthx2 = width*2;
  const gboolean markfixed = data->markfixed;
  const int min_neighbours = data->permissive ? 3 : 4;

  // The loop should output only a few pixels, so just copy everything first
  memcpy(o, i, roi_out->width*roi_out->height*sizeof(float));

  int fixed = 0;
#ifdef _OPENMP
  #pragma omp parallel for default(none) shared(roi_out, i, o) reduction(+:fixed) schedule(static)
#endif
  for (int row=2; row<roi_out->height-2; row++)
  {
    const float *in = (float*)i + width*row+2;
    float *out = (float*)o + width*row+2;
    for (int col=2; col<width-1; col++, in++, out++)
    {
      float mid= *in * multiplier;
      if (*in > threshold)
      {
        int count=0;
        float maxin=0.0;
        float other;
#define TESTONE(OFFSET)				\
	other=in[OFFSET];			\
	if (mid > other)			\
	{					\
	  count++;				\
	  if (other > maxin) maxin = other;	\
	}
        TESTONE(-2);
        TESTONE(-widthx2);
        TESTONE(+2);
        TESTONE(+widthx2);
#undef TESTONE
        if (count >= min_neighbours)
        {
          *out = maxin;
          fixed++;
          if (markfixed)
          {
            for (int i=-2; i>=-10 && i>=-col; i-=2)
              out[i] = *in;
            for (int i=2; i<=10 && i<width-col; i+=2)
              out[i] = *in;
          }
        }
      }
    }
  }
  if (g != NULL)
  {
    // lock gui thread mutex, if we are not called from gui thread (very likely)
    gboolean i_have_lock = dt_control_gdk_lock();
    char buf[256];
    snprintf(buf, sizeof buf, _("fixed %d pixels"), fixed);
    gtk_label_set_text(g->message, buf);
    if(i_have_lock) dt_control_gdk_unlock();
  }
}
예제 #20
0
int _camera_storage_image_filename(const dt_camera_t *camera,const char *filename,CameraFile *preview,CameraFile *exif,void *user_data)
{
  _camera_import_dialog_t *data=(_camera_import_dialog_t*)user_data;
  GtkTreeIter iter;
  const char *img;
  unsigned long size;
  GdkPixbuf *pixbuf=NULL;
  GdkPixbuf *thumb=NULL;

  /* stop fetching previews if job is cancelled */
  if (data->preview_job && dt_control_job_get_state(data->preview_job) == DT_JOB_STATE_CANCELLED )
    return 0;


  gboolean i_own_lock = dt_control_gdk_lock();
  char exif_info[1024]= {0};
  char file_info[4096]= {0};

  if( preview )
  {
    gp_file_get_data_and_size(preview, &img, &size);
    if( size > 0 )
    {
      // we got preview image data lets create a pixbuf from image blob
      GError *err=NULL;
      GInputStream *stream;
      if( (stream = g_memory_input_stream_new_from_data(img, size,NULL)) !=NULL)
        pixbuf = gdk_pixbuf_new_from_stream( stream, NULL, &err );
    }

    if(pixbuf)
    {
      // Scale pixbuf to a thumbnail
      double sw=gdk_pixbuf_get_width( pixbuf );
      double scale=75.0/gdk_pixbuf_get_height( pixbuf );
      thumb = gdk_pixbuf_scale_simple( pixbuf, sw*scale,75 , GDK_INTERP_BILINEAR );
    }
  }

#if 0
  // libgphoto only supports fetching exif in jpegs, not raw
  char buffer[1024]= {0};
  if ( exif )
  {
    const char *exif_data;
    char *value=NULL;
    gp_file_get_data_and_size(exif, &exif_data, &size);
    if( size > 0 )
    {
      void *exif=dt_exif_data_new((uint8_t *)exif_data,size);
      if( (value=g_strdup( dt_exif_data_get_value(exif,"Exif.Photo.ExposureTime",buffer,1024) ) ) != NULL);
      snprintf(exif_info, sizeof(exif_info), "exposure: %s\n", value);
    }
    else fprintf(stderr,"No exifdata read\n");
  }
#endif

  // filename\n 1/60 f/2.8 24mm iso 160
  snprintf(file_info, sizeof(file_info), "%s%c%s",filename,strlen(exif_info)?'\n':'\0',strlen(exif_info)?exif_info:"");
  gtk_list_store_append(data->store,&iter);
  gtk_list_store_set(data->store,&iter,0,thumb,1,file_info,-1);
  if(pixbuf) g_object_unref(pixbuf);
  if(thumb) g_object_ref(thumb);

  if (i_own_lock) dt_control_gdk_unlock();

  return 1;
}