void dt_lua_init(lua_State*L,const int init_gui) { char tmp_path[PATH_MAX]; // init the lua environment lua_CFunction* cur_type = init_funcs; while(*cur_type) { (*cur_type)(L); cur_type++; } dt_lua_push_darktable_lib(L); // build the table containing the configuration info lua_getglobal(L,"package"); dt_lua_goto_subtable(L,"loaded"); lua_pushstring(L,"darktable"); dt_lua_push_darktable_lib(L); lua_settable(L,-3); lua_pop(L,1); lua_getglobal(L,"package"); lua_getfield(L,-1,"path"); lua_pushstring(L,";"); dt_loc_get_datadir(tmp_path, PATH_MAX); lua_pushstring(L,tmp_path); lua_pushstring(L,"/lua/?.lua"); lua_pushstring(L,";"); dt_loc_get_user_config_dir(tmp_path, PATH_MAX); lua_pushstring(L,tmp_path); lua_pushstring(L,"/lua/?.lua"); lua_concat(L,7); lua_setfield(L,-2,"path"); lua_pop(L,1); if(init_gui) { // run global init script dt_loc_get_datadir(tmp_path, PATH_MAX); g_strlcat(tmp_path,"/rc.lua",PATH_MAX); dt_lua_dofile(darktable.lua_state,tmp_path); // run user init script dt_loc_get_user_config_dir(tmp_path, PATH_MAX); g_strlcat(tmp_path,"/rc.lua",PATH_MAX); dt_lua_dofile(darktable.lua_state,tmp_path); } }
static GVariant * _handle_get_property(GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *property_name, GError **error, gpointer user_data) { GVariant *ret; ret = NULL; if(!g_strcmp0(property_name, "DataDir")) { gchar datadir[PATH_MAX]; dt_loc_get_datadir(datadir, sizeof(datadir)); ret = g_variant_new_string(datadir); } else if(!g_strcmp0(property_name, "ConfigDir")) { gchar configdir[PATH_MAX]; dt_loc_get_user_config_dir(configdir, sizeof(configdir)); ret = g_variant_new_string(configdir); } return ret; }
void dt_styles_create_from_image (const char *name,const char *description,int32_t imgid,GList *filter) { int id=0; sqlite3_stmt *stmt; /* first create the style header */ if (!dt_styles_create_style_header(name,description) ) return; if ((id=dt_styles_get_id_by_name(name)) != 0) { /* create the style_items from source image history stack */ if (filter) { GList *list=filter; char tmp[64]; char include[2048]= {0}; g_strlcat(include,"num in (", 2048); do { if(list!=g_list_first(list)) g_strlcat(include,",", 2048); sprintf(tmp,"%ld",(long int)list->data); g_strlcat(include,tmp, 2048); } while ((list=g_list_next(list))); g_strlcat(include,")", 2048); char query[4096]= {0}; sprintf(query,"insert into style_items (styleid,num,module,operation,op_params,enabled,blendop_params,blendop_version,multi_priority,multi_name) select ?1, num,module,operation,op_params,enabled,blendop_params,blendop_version,multi_priority,multi_name from history where imgid=?2 and %s",include); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), query, -1, &stmt, NULL); } else DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "insert into style_items (styleid,num,module,operation,op_params,enabled,blendop_params,blendop_version,multi_priority,multi_name) select ?1, num,module,operation,op_params,enabled,blendop_params,blendop_version,multi_priority,multi_name from history where imgid=?2", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid); sqlite3_step (stmt); sqlite3_finalize (stmt); /* backup style to disk */ char stylesdir[1024]; dt_loc_get_user_config_dir(stylesdir, 1024); g_strlcat(stylesdir,"/styles",1024); g_mkdir_with_parents(stylesdir,00755); dt_styles_save_to_file(name,stylesdir,FALSE); char tmp_accel[1024]; gchar* tmp_name = g_strdup(name); // freed by _destro_style_shortcut_callback snprintf(tmp_accel,1024,"styles/Apply %s",name); dt_accel_register_global( tmp_accel, 0, 0); GClosure *closure; closure = g_cclosure_new( G_CALLBACK(_apply_style_shortcut_callback), tmp_name, _destroy_style_shortcut_callback); dt_accel_connect_global(tmp_accel, closure); dt_control_log(_("style named '%s' successfully created"),name); } }
void dt_lua_init(lua_State*L,const char *lua_command) { /* Note to reviewers this is the only place where lua code is run without the lua lock. At this point, no user script has been called, so we are completely thread-safe. no need to lock This is also the only place where lua code is run with the gdk lock held, but this is not a problem because it is very brief, user calls are delegated to a secondary job */ char tmp_path[PATH_MAX]; // init the lua environment lua_CFunction* cur_type = init_funcs; while(*cur_type) { (*cur_type)(L); cur_type++; } // build the table containing the configuration info lua_getglobal(L,"package"); dt_lua_goto_subtable(L,"loaded"); lua_pushstring(L,"darktable"); dt_lua_push_darktable_lib(L); lua_settable(L,-3); lua_pop(L,1); lua_getglobal(L,"package"); lua_getfield(L,-1,"path"); lua_pushstring(L,";"); dt_loc_get_datadir(tmp_path, sizeof(tmp_path)); lua_pushstring(L,tmp_path); lua_pushstring(L,"/lua/?.lua"); lua_pushstring(L,";"); dt_loc_get_user_config_dir(tmp_path, sizeof(tmp_path)); lua_pushstring(L,tmp_path); lua_pushstring(L,"/lua/?.lua"); lua_concat(L,7); lua_setfield(L,-2,"path"); lua_pop(L,1); dt_job_t *job = dt_control_job_create(&run_early_script, "lua: run initial script"); dt_control_job_set_params(job, g_strdup(lua_command)); if(darktable.gui) { dt_control_add_job(darktable.control, DT_JOB_QUEUE_USER_BG, job); } else { run_early_script(job); dt_control_job_dispose(job); } }
static void refresh_watermarks( dt_iop_module_t *self ) { dt_iop_watermark_gui_data_t *g = (dt_iop_watermark_gui_data_t *)self->gui_data; dt_iop_watermark_params_t *p = (dt_iop_watermark_params_t *)self->params; g_signal_handlers_block_by_func (g->combobox1,watermark_callback,self); // Clear combobox... GtkTreeModel *model=gtk_combo_box_get_model(g->combobox1); gtk_list_store_clear (GTK_LIST_STORE(model)); // check watermarkdir and update combo with entries... int count=0; const gchar *d_name = NULL; gchar configdir[DT_MAX_PATH_LEN]; gchar datadir[DT_MAX_PATH_LEN]; gchar filename[DT_MAX_PATH_LEN]; dt_loc_get_datadir(datadir, DT_MAX_PATH_LEN); dt_loc_get_user_config_dir(configdir, DT_MAX_PATH_LEN); g_strlcat(datadir,"/watermarks", DT_MAX_PATH_LEN); g_strlcat(configdir,"/watermarks", DT_MAX_PATH_LEN); /* read watermarks from datadir */ GDir *dir = g_dir_open(datadir, 0, NULL); if(dir) { while((d_name = g_dir_read_name(dir))) { snprintf(filename, DT_MAX_PATH_LEN, "%s/%s", datadir, d_name); gtk_combo_box_append_text( g->combobox1, d_name ); count++; } g_dir_close(dir) ; } /* read watermarks from user config dir*/ dir = g_dir_open(configdir, 0, NULL); if(dir) { while((d_name = g_dir_read_name(dir))) { snprintf(filename, DT_MAX_PATH_LEN, "%s/%s", configdir, d_name); gtk_combo_box_append_text( g->combobox1, d_name ); count++; } g_dir_close(dir) ; } _combo_box_set_active_text( g->combobox1, p->filename ); g_signal_handlers_unblock_by_func (g->combobox1,watermark_callback,self); }
void gui_init(struct dt_iop_module_t *self) { const int force_lcms2 = dt_conf_get_bool("plugins/lighttable/export/force_lcms2"); self->gui_data = calloc(1, sizeof(dt_iop_colorout_gui_data_t)); dt_iop_colorout_gui_data_t *g = (dt_iop_colorout_gui_data_t *)self->gui_data; char datadir[PATH_MAX] = { 0 }; char confdir[PATH_MAX] = { 0 }; dt_loc_get_datadir(datadir, sizeof(datadir)); dt_loc_get_user_config_dir(confdir, sizeof(confdir)); self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_BAUHAUS_SPACE); // TODO: g->output_intent = dt_bauhaus_combobox_new(self); gtk_box_pack_start(GTK_BOX(self->widget), g->output_intent, TRUE, TRUE, 0); dt_bauhaus_widget_set_label(g->output_intent, NULL, _("output intent")); dt_bauhaus_combobox_add(g->output_intent, _("perceptual")); dt_bauhaus_combobox_add(g->output_intent, _("relative colorimetric")); dt_bauhaus_combobox_add(g->output_intent, C_("rendering intent", "saturation")); dt_bauhaus_combobox_add(g->output_intent, _("absolute colorimetric")); if(!force_lcms2) { gtk_widget_set_no_show_all(g->output_intent, TRUE); gtk_widget_set_visible(g->output_intent, FALSE); } g->output_profile = dt_bauhaus_combobox_new(self); dt_bauhaus_widget_set_label(g->output_profile, NULL, _("output profile")); gtk_box_pack_start(GTK_BOX(self->widget), g->output_profile, TRUE, TRUE, 0); for(GList *l = darktable.color_profiles->profiles; l; l = g_list_next(l)) { dt_colorspaces_color_profile_t *prof = (dt_colorspaces_color_profile_t *)l->data; if(prof->out_pos > -1) dt_bauhaus_combobox_add(g->output_profile, prof->name); } char tooltip[1024]; g_object_set(G_OBJECT(g->output_intent), "tooltip-text", _("rendering intent"), (char *)NULL); snprintf(tooltip, sizeof(tooltip), _("ICC profiles in %s/color/out or %s/color/out"), confdir, datadir); g_object_set(G_OBJECT(g->output_profile), "tooltip-text", tooltip, (char *)NULL); g_signal_connect(G_OBJECT(g->output_intent), "value-changed", G_CALLBACK(intent_changed), (gpointer)self); g_signal_connect(G_OBJECT(g->output_profile), "value-changed", G_CALLBACK(output_profile_changed), (gpointer)self); // reload the profiles when the display or softproof profile changed! dt_control_signal_connect(darktable.signals, DT_SIGNAL_CONTROL_PROFILE_CHANGED, G_CALLBACK(_signal_profile_changed), self->dev); // update the gui when the preferences changed (i.e. show intent when using lcms2) dt_control_signal_connect(darktable.signals, DT_SIGNAL_PREFERENCES_CHANGE, G_CALLBACK(_preference_changed), (gpointer)self); }
void dt_lua_init(lua_State *L, const char *lua_command) { char tmp_path[PATH_MAX] = { 0 }; // init the lua environment lua_CFunction *cur_type = init_funcs; while(*cur_type) { (*cur_type)(L); cur_type++; } assert(lua_gettop(L) == 0); // if you are here, you have probably added an initialisation function that is not stack clean // build the table containing the configuration info lua_getglobal(L, "package"); dt_lua_goto_subtable(L, "loaded"); lua_pushstring(L, "darktable"); dt_lua_push_darktable_lib(L); lua_settable(L, -3); lua_pop(L, 1); lua_getglobal(L, "package"); lua_getfield(L, -1, "path"); lua_pushstring(L, ";"); dt_loc_get_datadir(tmp_path, sizeof(tmp_path)); lua_pushstring(L, tmp_path); lua_pushstring(L, "/lua/?.lua"); lua_pushstring(L, ";"); dt_loc_get_user_config_dir(tmp_path, sizeof(tmp_path)); lua_pushstring(L, tmp_path); lua_pushstring(L, "/lua/?.lua"); lua_concat(L, 7); lua_setfield(L, -2, "path"); lua_pop(L, 1); lua_pushcfunction(L,run_early_script); lua_pushstring(L,lua_command); if(darktable.gui) { dt_lua_do_chunk_later(L,1); } else { dt_lua_do_chunk_silent(L,1,0); } // allow other threads to wake up and do their job dt_lua_unlock(); }
static void refresh_watermarks(dt_iop_module_t *self) { dt_iop_watermark_gui_data_t *g = (dt_iop_watermark_gui_data_t *)self->gui_data; dt_iop_watermark_params_t *p = (dt_iop_watermark_params_t *)self->params; g_signal_handlers_block_by_func(g->watermarks, watermark_callback, self); // Clear combobox... dt_bauhaus_combobox_clear(g->watermarks); // check watermarkdir and update combo with entries... int count = 0; const gchar *d_name = NULL; gchar configdir[PATH_MAX] = { 0 }; gchar datadir[PATH_MAX] = { 0 }; gchar filename[PATH_MAX] = { 0 }; dt_loc_get_datadir(datadir, sizeof(datadir)); dt_loc_get_user_config_dir(configdir, sizeof(configdir)); g_strlcat(datadir, "/watermarks", sizeof(datadir)); g_strlcat(configdir, "/watermarks", sizeof(configdir)); /* read watermarks from datadir */ GDir *dir = g_dir_open(datadir, 0, NULL); if(dir) { while((d_name = g_dir_read_name(dir))) { snprintf(filename, sizeof(filename), "%s/%s", datadir, d_name); dt_bauhaus_combobox_add(g->watermarks, d_name); count++; } g_dir_close(dir); } /* read watermarks from user config dir*/ dir = g_dir_open(configdir, 0, NULL); if(dir) { while((d_name = g_dir_read_name(dir))) { snprintf(filename, sizeof(filename), "%s/%s", configdir, d_name); dt_bauhaus_combobox_add(g->watermarks, d_name); count++; } g_dir_close(dir); } _combo_box_set_active_text(g->watermarks, p->filename); g_signal_handlers_unblock_by_func(g->watermarks, watermark_callback, self); }
int dt_colorspaces_find_profile(char *filename, const int filename_len, const char *profile, const char *inout) { char datadir[DT_MAX_PATH_LEN]; dt_loc_get_user_config_dir(datadir, DT_MAX_PATH_LEN); snprintf(filename, filename_len, "%s/color/%s/%s", datadir, inout, profile); if(!g_file_test(filename, G_FILE_TEST_IS_REGULAR)) { dt_loc_get_datadir(datadir, DT_MAX_PATH_LEN); snprintf(filename, filename_len, "%s/color/%s/%s", datadir, inout, profile); if(!g_file_test(filename, G_FILE_TEST_IS_REGULAR)) return 1; } return 0; }
static int run_early_script(lua_State* L) { char tmp_path[PATH_MAX] = { 0 }; // run global init script dt_loc_get_datadir(tmp_path, sizeof(tmp_path)); g_strlcat(tmp_path, "/luarc", sizeof(tmp_path)); dt_lua_dofile_silent(L, tmp_path, 0, 0); if(darktable.gui != NULL) { // run user init script dt_loc_get_user_config_dir(tmp_path, sizeof(tmp_path)); g_strlcat(tmp_path, "/luarc", sizeof(tmp_path)); dt_lua_dofile_silent(L, tmp_path, 0, 0); } if(!lua_isnil(L,1)){ const char *lua_command = lua_tostring(L, 1); dt_lua_dostring_silent(L, lua_command, 0, 0); } dt_lua_redraw_screen(); return 0; }
int dt_lua_init_configuration(lua_State*L){ char tmp_path[PATH_MAX]; dt_lua_push_darktable_lib(L); dt_lua_goto_subtable(L,"configuration"); // build the table containing the configuration info lua_pushstring(L,"tmp_dir"); dt_loc_get_tmp_dir(tmp_path, PATH_MAX); lua_pushstring(L,tmp_path); lua_settable(L,-3); lua_pushstring(L,"config_dir"); dt_loc_get_user_config_dir(tmp_path, PATH_MAX); lua_pushstring(L,tmp_path); lua_settable(L,-3); lua_pushstring(L,"cache_dir"); dt_loc_get_user_cache_dir(tmp_path, PATH_MAX); lua_pushstring(L,tmp_path); lua_settable(L,-3); lua_pushstring(L,"version"); lua_pushstring(darktable.lua_state,PACKAGE_VERSION); lua_settable(L,-3); lua_pushstring(L,"verbose"); lua_pushboolean(L,darktable.unmuted & DT_DEBUG_LUA); lua_settable(L,-3); lua_pushstring(L,"has_gui"); lua_pushboolean(L,darktable.gui != NULL); lua_settable(L,-3); lua_pop(L,-1); //remove the configuration table from the stack return 0; }
static int run_early_script(lua_State* L) { char basedir[PATH_MAX] = { 0 }; // run global init script dt_loc_get_datadir(basedir, sizeof(basedir)); char *luarc = g_build_filename(basedir, "luarc", NULL); dt_lua_check_print_error(L, luaL_dofile(L, luarc)); g_free(luarc); if(darktable.gui != NULL) { // run user init script dt_loc_get_user_config_dir(basedir, sizeof(basedir)); luarc = g_build_filename(basedir, "luarc", NULL); dt_lua_check_print_error(L, luaL_dofile(L, luarc)); g_free(luarc); } if(!lua_isnil(L,1)){ const char *lua_command = lua_tostring(L, 1); dt_lua_check_print_error(L,luaL_dostring(L,lua_command)); } dt_lua_redraw_screen(); return 0; }
static int32_t run_early_script(dt_job_t *job) { char tmp_path[PATH_MAX]; lua_State *L = darktable.lua_state.state; gboolean has_lock = dt_lua_lock(); // run global init script dt_loc_get_datadir(tmp_path, sizeof(tmp_path)); g_strlcat(tmp_path, "/luarc", sizeof(tmp_path)); dt_lua_dofile_silent(L,tmp_path,0,0); if(darktable.gui != NULL) { // run user init script dt_loc_get_user_config_dir(tmp_path, sizeof(tmp_path)); g_strlcat(tmp_path, "/luarc", sizeof(tmp_path)); dt_lua_dofile_silent(L,tmp_path,0,0); } char *lua_command = dt_control_job_get_params(job); if(lua_command) dt_lua_dostring_silent(L, lua_command, 0, 0); free(lua_command); dt_lua_redraw_screen(); dt_lua_unlock(has_lock); return 0; }
int dt_gui_gtk_init(dt_gui_gtk_t *gui, int argc, char *argv[]) { // unset gtk rc from kde: char gtkrc[PATH_MAX], path[PATH_MAX], datadir[PATH_MAX], configdir[PATH_MAX]; dt_loc_get_datadir(datadir, PATH_MAX); dt_loc_get_user_config_dir(configdir, PATH_MAX); g_snprintf(gtkrc, PATH_MAX, "%s/darktable.gtkrc", configdir); if (!g_file_test(gtkrc, G_FILE_TEST_EXISTS)) g_snprintf(gtkrc, PATH_MAX, "%s/darktable.gtkrc", datadir); if (g_file_test(gtkrc, G_FILE_TEST_EXISTS)) (void)setenv("GTK2_RC_FILES", gtkrc, 1); else fprintf(stderr, "[gtk_init] could not found darktable.gtkrc"); /* lets zero mem */ memset(gui,0,sizeof(dt_gui_gtk_t)); #if GLIB_MAJOR_VERSION <= 2 #if GLIB_MINOR_VERSION < 31 if (!g_thread_supported ()) g_thread_init(NULL); #endif #endif gdk_threads_init(); gdk_threads_enter(); gtk_init (&argc, &argv); GtkWidget *widget; gui->ui = dt_ui_initialize(argc,argv); gui->pixmap = NULL; gui->center_tooltip = 0; gui->presets_popup_menu = NULL; if(g_file_test(gtkrc, G_FILE_TEST_EXISTS)) gtk_rc_parse (gtkrc); // Initializing the shortcut groups darktable.control->accelerators = gtk_accel_group_new(); darktable.control->accelerator_list = NULL; // Connecting the callback to update keyboard accels for key_pressed g_signal_connect(G_OBJECT(gtk_accel_map_get()), "changed", G_CALLBACK(key_accel_changed), NULL); // Initializing widgets init_widgets(); // Adding the global shortcut group to the main window gtk_window_add_accel_group(GTK_WINDOW(dt_ui_main_window(darktable.gui->ui)), darktable.control->accelerators); // get the screen resolution gui->dpi = gdk_screen_get_resolution(gtk_widget_get_screen(GTK_WIDGET(dt_ui_main_window(darktable.gui->ui)))); // set constant width from conf key int panel_width = dt_conf_get_int("panel_width"); if(panel_width < 20 || panel_width > 500) { // fix for unset/insane values. panel_width = 300; dt_conf_set_int("panel_width", panel_width); } // dt_gui_background_jobs_init(); /* Have the delete event (window close) end the program */ dt_loc_get_datadir(datadir, PATH_MAX); snprintf(path, PATH_MAX, "%s/icons", datadir); gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (), path); widget = dt_ui_center(darktable.gui->ui); g_signal_connect (G_OBJECT (widget), "key-press-event", G_CALLBACK (key_pressed), NULL); g_signal_connect (G_OBJECT (widget), "configure-event", G_CALLBACK (configure), NULL); g_signal_connect (G_OBJECT (widget), "expose-event", G_CALLBACK (expose), NULL); g_signal_connect (G_OBJECT (widget), "motion-notify-event", G_CALLBACK (mouse_moved), NULL); g_signal_connect (G_OBJECT (widget), "leave-notify-event", G_CALLBACK (center_leave), NULL); g_signal_connect (G_OBJECT (widget), "enter-notify-event", G_CALLBACK (center_enter), NULL); g_signal_connect (G_OBJECT (widget), "button-press-event", G_CALLBACK (button_pressed), NULL); g_signal_connect (G_OBJECT (widget), "button-release-event", G_CALLBACK (button_released), NULL); g_signal_connect (G_OBJECT (widget), "scroll-event", G_CALLBACK (scrolled), NULL); // TODO: left, right, top, bottom: //leave-notify-event widget = darktable.gui->widgets.left_border; g_signal_connect (G_OBJECT (widget), "expose-event", G_CALLBACK (expose_borders), (gpointer)0); g_signal_connect (G_OBJECT (widget), "button-press-event", G_CALLBACK (borders_button_pressed), darktable.gui->ui); g_signal_connect (G_OBJECT (widget), "scroll-event", G_CALLBACK (borders_scrolled), (gpointer)0); g_object_set_data(G_OBJECT (widget), "border", (gpointer)0); widget = darktable.gui->widgets.right_border; g_signal_connect (G_OBJECT (widget), "expose-event", G_CALLBACK (expose_borders), (gpointer)1); g_signal_connect (G_OBJECT (widget), "button-press-event", G_CALLBACK (borders_button_pressed), darktable.gui->ui); g_signal_connect (G_OBJECT (widget), "scroll-event", G_CALLBACK (borders_scrolled), (gpointer)1); g_object_set_data(G_OBJECT (widget), "border", (gpointer)1); widget = darktable.gui->widgets.top_border; g_signal_connect (G_OBJECT (widget), "expose-event", G_CALLBACK (expose_borders), (gpointer)2); g_signal_connect (G_OBJECT (widget), "button-press-event", G_CALLBACK (borders_button_pressed), darktable.gui->ui); g_signal_connect (G_OBJECT (widget), "scroll-event", G_CALLBACK (borders_scrolled), (gpointer)2); g_object_set_data(G_OBJECT (widget), "border", (gpointer)2); widget = darktable.gui->widgets.bottom_border; g_signal_connect (G_OBJECT (widget), "expose-event", G_CALLBACK (expose_borders), (gpointer)3); g_signal_connect (G_OBJECT (widget), "button-press-event", G_CALLBACK (borders_button_pressed), darktable.gui->ui); g_signal_connect (G_OBJECT (widget), "scroll-event", G_CALLBACK (borders_scrolled), (gpointer)3); g_object_set_data(G_OBJECT (widget), "border", (gpointer)3); dt_gui_presets_init(); widget = dt_ui_center(darktable.gui->ui); GTK_WIDGET_UNSET_FLAGS (widget, GTK_DOUBLE_BUFFERED); // GTK_WIDGET_SET_FLAGS (widget, GTK_DOUBLE_BUFFERED); GTK_WIDGET_SET_FLAGS (widget, GTK_APP_PAINTABLE); // TODO: make this work as: libgnomeui testgnome.c /* GtkContainer *box = GTK_CONTAINER(darktable.gui->widgets.plugins_vbox); GtkScrolledWindow *swin = GTK_SCROLLED_WINDOW(darktable.gui-> widgets.right_scrolled_window); gtk_container_set_focus_vadjustment (box, gtk_scrolled_window_get_vadjustment (swin)); */ dt_ctl_get_display_profile(widget, &darktable.control->xprofile_data, &darktable.control->xprofile_size); // register keys for view switching dt_accel_register_global(NC_("accel", "capture view"), GDK_t, 0); dt_accel_register_global(NC_("accel", "lighttable view"), GDK_l, 0); dt_accel_register_global(NC_("accel", "darkroom view"), GDK_d, 0); dt_accel_connect_global( "capture view", g_cclosure_new(G_CALLBACK(_gui_switch_view_key_accel_callback), (gpointer)DT_GUI_VIEW_SWITCH_TO_TETHERING, NULL)); dt_accel_connect_global( "lighttable view", g_cclosure_new(G_CALLBACK(_gui_switch_view_key_accel_callback), (gpointer)DT_GUI_VIEW_SWITCH_TO_LIBRARY, NULL)); dt_accel_connect_global( "darkroom view", g_cclosure_new(G_CALLBACK(_gui_switch_view_key_accel_callback), (gpointer)DT_GUI_VIEW_SWITCH_TO_DARKROOM, NULL)); // register_keys for applying styles init_styles_key_accels(); connect_styles_key_accels(); // register ctrl-q to quit: dt_accel_register_global(NC_("accel", "quit"), GDK_q, GDK_CONTROL_MASK); dt_accel_connect_global( "quit", g_cclosure_new(G_CALLBACK(quit_callback), NULL, NULL)); // Contrast and brightness accelerators dt_accel_register_global(NC_("accel", "increase brightness"), GDK_F10, 0); dt_accel_register_global(NC_("accel", "decrease brightness"), GDK_F9, 0); dt_accel_register_global(NC_("accel", "increase contrast"), GDK_F8, 0); dt_accel_register_global(NC_("accel", "decrease contrast"), GDK_F7, 0); dt_accel_connect_global( "increase brightness", g_cclosure_new(G_CALLBACK(brightness_key_accel_callback), (gpointer)1, NULL)); dt_accel_connect_global( "decrease brightness", g_cclosure_new(G_CALLBACK(brightness_key_accel_callback), (gpointer)0, NULL)); dt_accel_connect_global( "increase contrast", g_cclosure_new(G_CALLBACK(contrast_key_accel_callback), (gpointer)1, NULL)); dt_accel_connect_global( "decrease contrast", g_cclosure_new(G_CALLBACK(contrast_key_accel_callback), (gpointer)0, NULL)); // Full-screen accelerators dt_accel_register_global(NC_("accel", "toggle fullscreen"), GDK_F11, 0); dt_accel_register_global(NC_("accel", "leave fullscreen"), GDK_Escape, 0); dt_accel_connect_global( "toggle fullscreen", g_cclosure_new(G_CALLBACK(fullscreen_key_accel_callback), (gpointer)1, NULL)); dt_accel_connect_global( "leave fullscreen", g_cclosure_new(G_CALLBACK(fullscreen_key_accel_callback), (gpointer)0, NULL)); // Side-border hide/show dt_accel_register_global(NC_("accel", "toggle side borders"), GDK_Tab, 0); // toggle view of header dt_accel_register_global(NC_("accel", "toggle header"), GDK_h, GDK_CONTROL_MASK); // View-switch dt_accel_register_global(NC_("accel", "switch view"), GDK_period, 0); dt_accel_connect_global( "switch view", g_cclosure_new(G_CALLBACK(view_switch_key_accel_callback), NULL, NULL)); darktable.gui->reset = 0; for(int i=0; i<3; i++) darktable.gui->bgcolor[i] = 0.1333; /* apply contrast to theme */ dt_gui_contrast_init (); return 0; }
static gchar *_watermark_get_svgdoc(dt_iop_module_t *self, dt_iop_watermark_data_t *data, const dt_image_t *image) { gsize length; gchar *svgdoc = NULL; gchar configdir[PATH_MAX] = { 0 }; gchar datadir[PATH_MAX] = { 0 }; gchar *filename; dt_loc_get_datadir(datadir, sizeof(datadir)); dt_loc_get_user_config_dir(configdir, sizeof(configdir)); g_strlcat(datadir, "/watermarks/", sizeof(datadir)); g_strlcat(configdir, "/watermarks/", sizeof(configdir)); g_strlcat(datadir, data->filename, sizeof(datadir)); g_strlcat(configdir, data->filename, sizeof(configdir)); if(g_file_test(configdir, G_FILE_TEST_EXISTS)) filename = configdir; else if(g_file_test(datadir, G_FILE_TEST_EXISTS)) filename = datadir; else return NULL; gchar *svgdata = NULL; char datetime[200]; // EXIF datetime struct tm tt_exif = { 0 }; if(sscanf(image->exif_datetime_taken, "%d:%d:%d %d:%d:%d", &tt_exif.tm_year, &tt_exif.tm_mon, &tt_exif.tm_mday, &tt_exif.tm_hour, &tt_exif.tm_min, &tt_exif.tm_sec) == 6) { tt_exif.tm_year -= 1900; tt_exif.tm_mon--; } // Current datetime struct tm tt_cur = { 0 }; time_t t = time(NULL); (void)localtime_r(&t, &tt_cur); if(g_file_get_contents(filename, &svgdata, &length, NULL)) { // File is loaded lets substitute strings if found... // Darktable internal svgdoc = _string_substitute(svgdata, "$(DARKTABLE.NAME)", PACKAGE_NAME); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } svgdoc = _string_substitute(svgdata, "$(DARKTABLE.VERSION)", PACKAGE_VERSION); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } // Simple text from watermark module gchar buffer[1024]; if (data->font[0] && data->text[0]) { g_snprintf(buffer, sizeof(buffer), "%s", data->text); svgdoc = _string_substitute(svgdata, "$(WATERMARK_TEXT)", buffer); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } PangoFontDescription *font = pango_font_description_from_string(data->font); const PangoStyle font_style = pango_font_description_get_style(font); const int font_weight = (int)pango_font_description_get_weight(font); g_snprintf(buffer, sizeof(buffer), "%s", pango_font_description_get_family(font)); svgdoc = _string_substitute(svgdata, "$(WATERMARK_FONT_FAMILY)", buffer); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } switch (font_style) { case PANGO_STYLE_OBLIQUE: g_strlcpy(buffer, "oblique", sizeof(buffer)); break; case PANGO_STYLE_ITALIC: g_strlcpy(buffer, "italic", sizeof(buffer)); break; default: g_strlcpy(buffer, "normal", sizeof(buffer)); break; } svgdoc = _string_substitute(svgdata, "$(WATERMARK_FONT_STYLE)", buffer); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } g_snprintf(buffer, sizeof(buffer), "%d", font_weight); svgdoc = _string_substitute(svgdata, "$(WATERMARK_FONT_WEIGHT)", buffer); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } pango_font_description_free(font); } // watermark color GdkRGBA c = { data->color[0], data->color[1], data->color[2], 1.0f }; g_snprintf(buffer, sizeof(buffer), "%s", gdk_rgba_to_string(&c)); svgdoc = _string_substitute(svgdata, "$(WATERMARK_COLOR)", buffer); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } // Current image ID g_snprintf(buffer, sizeof(buffer), "%d", image->id); svgdoc = _string_substitute(svgdata, "$(IMAGE.ID)", buffer); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } // Current image dt_image_print_exif(image, buffer, sizeof(buffer)); svgdoc = _string_substitute(svgdata, "$(IMAGE.EXIF)", buffer); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } // Image exif // EXIF date svgdoc = _string_substitute(svgdata, "$(EXIF.DATE)", image->exif_datetime_taken); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } // $(EXIF.DATE.SECOND) -- 00..60 strftime(datetime, sizeof(datetime), "%S", &tt_exif); svgdoc = _string_substitute(svgdata, "$(EXIF.DATE.SECOND)", datetime); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } // $(EXIF.DATE.MINUTE) -- 00..59 strftime(datetime, sizeof(datetime), "%M", &tt_exif); svgdoc = _string_substitute(svgdata, "$(EXIF.DATE.MINUTE)", datetime); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } // $(EXIF.DATE.HOUR) -- 00..23 strftime(datetime, sizeof(datetime), "%H", &tt_exif); svgdoc = _string_substitute(svgdata, "$(EXIF.DATE.HOUR)", datetime); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } // $(EXIF.DATE.HOUR_AMPM) -- 01..12 strftime(datetime, sizeof(datetime), "%I %p", &tt_exif); svgdoc = _string_substitute(svgdata, "$(EXIF.DATE.HOUR_AMPM)", datetime); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } // $(EXIF.DATE.DAY) -- 01..31 strftime(datetime, sizeof(datetime), "%d", &tt_exif); svgdoc = _string_substitute(svgdata, "$(EXIF.DATE.DAY)", datetime); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } // $(EXIF.DATE.MONTH) -- 01..12 strftime(datetime, sizeof(datetime), "%m", &tt_exif); svgdoc = _string_substitute(svgdata, "$(EXIF.DATE.MONTH)", datetime); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } // $(EXIF.DATE.SHORT_MONTH) -- Jan, Feb, .., Dec, localized strftime(datetime, sizeof(datetime), "%b", &tt_exif); svgdoc = _string_substitute(svgdata, "$(EXIF.DATE.SHORT_MONTH)", datetime); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } // $(EXIF.DATE.LONG_MONTH) -- January, February, .., December, localized strftime(datetime, sizeof(datetime), "%B", &tt_exif); svgdoc = _string_substitute(svgdata, "$(EXIF.DATE.LONG_MONTH)", datetime); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } // $(EXIF.DATE.SHORT_YEAR) -- 12 strftime(datetime, sizeof(datetime), "%y", &tt_exif); svgdoc = _string_substitute(svgdata, "$(EXIF.DATE.SHORT_YEAR)", datetime); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } // $(EXIF.DATE.LONG_YEAR) -- 2012 strftime(datetime, sizeof(datetime), "%Y", &tt_exif); svgdoc = _string_substitute(svgdata, "$(EXIF.DATE.LONG_YEAR)", datetime); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } // Current date // $(DATE) -- YYYY: dt_gettime_t(datetime, sizeof(datetime), t); svgdoc = _string_substitute(svgdata, "$(DATE)", datetime); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } // $(DATE.SECOND) -- 00..60 strftime(datetime, sizeof(datetime), "%S", &tt_cur); svgdoc = _string_substitute(svgdata, "$(DATE.SECOND)", datetime); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } // $(DATE.MINUTE) -- 00..59 strftime(datetime, sizeof(datetime), "%M", &tt_cur); svgdoc = _string_substitute(svgdata, "$(DATE.MINUTE)", datetime); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } // $(DATE.HOUR) -- 00..23 strftime(datetime, sizeof(datetime), "%H", &tt_cur); svgdoc = _string_substitute(svgdata, "$(DATE.HOUR)", datetime); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } // $(DATE.HOUR_AMPM) -- 01..12 strftime(datetime, sizeof(datetime), "%I %p", &tt_cur); svgdoc = _string_substitute(svgdata, "$(DATE.HOUR_AMPM)", datetime); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } // $(DATE.DAY) -- 01..31 strftime(datetime, sizeof(datetime), "%d", &tt_cur); svgdoc = _string_substitute(svgdata, "$(DATE.DAY)", datetime); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } // $(DATE.MONTH) -- 01..12 strftime(datetime, sizeof(datetime), "%m", &tt_cur); svgdoc = _string_substitute(svgdata, "$(DATE.MONTH)", datetime); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } // $(DATE.SHORT_MONTH) -- Jan, Feb, .., Dec, localized strftime(datetime, sizeof(datetime), "%b", &tt_cur); svgdoc = _string_substitute(svgdata, "$(DATE.SHORT_MONTH)", datetime); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } // $(DATE.LONG_MONTH) -- January, February, .., December, localized strftime(datetime, sizeof(datetime), "%B", &tt_cur); svgdoc = _string_substitute(svgdata, "$(DATE.LONG_MONTH)", datetime); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } // $(DATE.SHORT_YEAR) -- 12 strftime(datetime, sizeof(datetime), "%y", &tt_cur); svgdoc = _string_substitute(svgdata, "$(DATE.SHORT_YEAR)", datetime); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } // $(DATE.LONG_YEAR) -- 2012 strftime(datetime, sizeof(datetime), "%Y", &tt_cur); svgdoc = _string_substitute(svgdata, "$(DATE.LONG_YEAR)", datetime); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } svgdoc = _string_substitute(svgdata, "$(EXIF.MAKER)", image->camera_maker); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } svgdoc = _string_substitute(svgdata, "$(EXIF.MODEL)", image->camera_model); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } svgdoc = _string_substitute(svgdata, "$(EXIF.LENS)", image->exif_lens); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } svgdoc = _string_substitute(svgdata, "$(IMAGE.FILENAME)", image->filename); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } gchar *basename = g_path_get_basename(image->filename); if(g_strrstr(basename, ".")) *(g_strrstr(basename, ".")) = '\0'; svgdoc = _string_substitute(svgdata, "$(IMAGE.BASENAME)", basename); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } g_free(basename); // TODO: auto generate that code? GList *res; res = dt_metadata_get(image->id, "Xmp.dc.creator", NULL); svgdoc = _string_substitute(svgdata, "$(Xmp.dc.creator)", (res ? res->data : "")); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } if(res) { g_list_free_full(res, &g_free); } res = dt_metadata_get(image->id, "Xmp.dc.publisher", NULL); svgdoc = _string_substitute(svgdata, "$(Xmp.dc.publisher)", (res ? res->data : "")); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } if(res) { g_list_free_full(res, &g_free); } res = dt_metadata_get(image->id, "Xmp.dc.title", NULL); svgdoc = _string_substitute(svgdata, "$(Xmp.dc.title)", (res ? res->data : "")); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } if(res) { g_list_free_full(res, &g_free); } res = dt_metadata_get(image->id, "Xmp.dc.description", NULL); svgdoc = _string_substitute(svgdata, "$(Xmp.dc.description)", (res ? res->data : "")); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } if(res) { g_list_free_full(res, &g_free); } res = dt_metadata_get(image->id, "Xmp.dc.rights", NULL); svgdoc = _string_substitute(svgdata, "$(Xmp.dc.rights)", (res ? res->data : "")); if(svgdoc != svgdata) { g_free(svgdata); svgdata = svgdoc; } if(res) { g_list_free_full(res, &g_free); } } return svgdoc; }
void gui_init(struct dt_iop_module_t *self) { self->gui_data = malloc(sizeof(dt_iop_watermark_gui_data_t)); dt_iop_watermark_gui_data_t *g = (dt_iop_watermark_gui_data_t *)self->gui_data; dt_iop_watermark_params_t *p = (dt_iop_watermark_params_t *)self->params; int line = 0; self->widget = gtk_grid_new(); gtk_grid_set_row_spacing(GTK_GRID(self->widget), DT_BAUHAUS_SPACE); gtk_grid_set_column_spacing(GTK_GRID(self->widget), DT_PIXEL_APPLY_DPI(10)); gtk_grid_attach(GTK_GRID(self->widget), dt_ui_section_label_new(_("content")), 0, line++, 3, 1); // Add the marker combobox gchar configdir[PATH_MAX] = { 0 }; gchar datadir[PATH_MAX] = { 0 }; dt_loc_get_datadir(datadir, sizeof(datadir)); dt_loc_get_user_config_dir(configdir, sizeof(configdir)); GtkWidget *label = dtgtk_reset_label_new(_("marker"), self, &p->filename, sizeof(p->filename)); g->watermarks = dt_bauhaus_combobox_new(self); gtk_widget_set_hexpand(GTK_WIDGET(g->watermarks), TRUE); char *tooltip = g_strdup_printf(_("SVG watermarks in %s/watermarks or %s/watermarks"), configdir, datadir); gtk_widget_set_tooltip_text(g->watermarks, tooltip); g_free(tooltip); g->refresh = dtgtk_button_new(dtgtk_cairo_paint_refresh, CPF_STYLE_FLAT | CPF_DO_NOT_USE_BORDER); gtk_grid_attach(GTK_GRID(self->widget), label, 0, line++, 1, 1); gtk_grid_attach_next_to(GTK_GRID(self->widget), g->watermarks, label, GTK_POS_RIGHT, 1, 1); gtk_grid_attach_next_to(GTK_GRID(self->widget), g->refresh, g->watermarks, GTK_POS_RIGHT, 1, 1); // Watermark color float red = dt_conf_get_float("plugins/darkroom/watermark/color_red"); float green = dt_conf_get_float("plugins/darkroom/watermark/color_green"); float blue = dt_conf_get_float("plugins/darkroom/watermark/color_blue"); GdkRGBA color = (GdkRGBA){.red = red, .green = green, .blue = blue, .alpha = 1.0 }; label = dtgtk_reset_label_new(_("color"), self, &p->color, 3 * sizeof(float)); g->colorpick = gtk_color_button_new_with_rgba(&color); gtk_widget_set_tooltip_text(g->colorpick, _("watermark color, tag:\n$(WATERMARK_COLOR)")); gtk_color_chooser_set_use_alpha(GTK_COLOR_CHOOSER(g->colorpick), FALSE); gtk_widget_set_size_request(GTK_WIDGET(g->colorpick), DT_PIXEL_APPLY_DPI(24), DT_PIXEL_APPLY_DPI(24)); gtk_color_button_set_title(GTK_COLOR_BUTTON(g->colorpick), _("select watermark color")); gtk_grid_attach(GTK_GRID(self->widget), label, 0, line++, 1, 1); gtk_grid_attach_next_to(GTK_GRID(self->widget), g->colorpick, label, GTK_POS_RIGHT, 2, 1); // Simple text label = gtk_label_new(_("text")); gtk_widget_set_halign(label, GTK_ALIGN_START); g->text = gtk_entry_new(); gtk_entry_set_width_chars(GTK_ENTRY(g->text), 1); gtk_widget_set_tooltip_text(g->text, _("text string, tag:\n$(WATERMARK_TEXT)")); dt_gui_key_accel_block_on_focus_connect(g->text); gtk_grid_attach(GTK_GRID(self->widget), label, 0, line++, 1, 1); gtk_grid_attach_next_to(GTK_GRID(self->widget), g->text, label, GTK_POS_RIGHT, 2, 1); gchar *str = dt_conf_get_string("plugins/darkroom/watermark/text"); gtk_entry_set_text(GTK_ENTRY(g->text), str); g_free(str); // Text font label = dtgtk_reset_label_new(_("font"), self, &p->font, sizeof(p->font)); str = dt_conf_get_string("plugins/darkroom/watermark/font"); g->fontsel = gtk_font_button_new_with_font(str==NULL?"DejaVu Sans 10":str); GList *childs = gtk_container_get_children(GTK_CONTAINER(gtk_bin_get_child(GTK_BIN(g->fontsel)))); gtk_label_set_ellipsize(GTK_LABEL(childs->data), PANGO_ELLIPSIZE_MIDDLE); g_list_free(childs); gtk_widget_set_tooltip_text(g->fontsel, _("text font, tags:\n$(WATERMARK_FONT_FAMILY)\n" "$(WATERMARK_FONT_STYLE)\n$(WATERMARK_FONT_WEIGHT)")); gtk_font_button_set_show_size (GTK_FONT_BUTTON(g->fontsel), FALSE); g_free(str); gtk_grid_attach(GTK_GRID(self->widget), label, 0, line++, 1, 1); gtk_grid_attach_next_to(GTK_GRID(self->widget), g->fontsel, label, GTK_POS_RIGHT, 2, 1); gtk_grid_attach(GTK_GRID(self->widget), dt_ui_section_label_new(_("properties")), 0, line++, 3, 1); // Add opacity/scale sliders to table g->opacity = dt_bauhaus_slider_new_with_range(self, 0.0, 100.0, 1.0, p->opacity, 0); dt_bauhaus_slider_set_format(g->opacity, "%.f%%"); dt_bauhaus_widget_set_label(g->opacity, NULL, _("opacity")); g->scale = dt_bauhaus_slider_new_with_range(self, 1.0, 100.0, 1.0, p->scale, 0); dt_bauhaus_slider_enable_soft_boundaries(g->scale, 1.0, 500.0); dt_bauhaus_slider_set_format(g->scale, "%.f%%"); dt_bauhaus_widget_set_label(g->scale, NULL, _("scale")); g->rotate = dt_bauhaus_slider_new_with_range(self, -180.0, 180.0, 1.0, p->rotate, 2); dt_bauhaus_slider_set_format(g->rotate, "%.02f°"); dt_bauhaus_widget_set_label(g->rotate, NULL, _("rotation")); gtk_grid_attach(GTK_GRID(self->widget), g->opacity, 0, line++, 3, 1); gtk_grid_attach(GTK_GRID(self->widget), g->scale, 0, line++, 3, 1); gtk_grid_attach(GTK_GRID(self->widget), g->rotate, 0, line++, 3, 1); g->sizeto = dt_bauhaus_combobox_new(self); dt_bauhaus_combobox_add(g->sizeto, C_("size", "image")); dt_bauhaus_combobox_add(g->sizeto, _("larger border")); dt_bauhaus_combobox_add(g->sizeto, _("smaller border")); dt_bauhaus_combobox_set(g->sizeto, p->sizeto); dt_bauhaus_widget_set_label(g->sizeto, NULL, _("scale on")); gtk_widget_set_tooltip_text(g->sizeto, _("size is relative to")); gtk_grid_attach(GTK_GRID(self->widget), g->sizeto, 0, line++, 3, 1); gtk_grid_attach(GTK_GRID(self->widget), dt_ui_section_label_new(_("position")), 0, line++, 3, 1); // Create the 3x3 gtk table toggle button table... label = dtgtk_reset_label_new(_("alignment"), self, &p->alignment, sizeof(p->alignment)); GtkWidget *bat = gtk_grid_new(); gtk_grid_set_row_spacing(GTK_GRID(bat), DT_PIXEL_APPLY_DPI(3)); gtk_grid_set_column_spacing(GTK_GRID(bat), DT_PIXEL_APPLY_DPI(3)); for(int i = 0; i < 9; i++) { g->align[i] = dtgtk_togglebutton_new(dtgtk_cairo_paint_alignment, CPF_STYLE_FLAT | (CPF_SPECIAL_FLAG << i)); gtk_widget_set_size_request(GTK_WIDGET(g->align[i]), DT_PIXEL_APPLY_DPI(16), DT_PIXEL_APPLY_DPI(16)); gtk_grid_attach(GTK_GRID(bat), GTK_WIDGET(g->align[i]), i%3, i/3, 1, 1); g_signal_connect(G_OBJECT(g->align[i]), "toggled", G_CALLBACK(alignment_callback), self); } gtk_grid_attach(GTK_GRID(self->widget), label, 0, line++, 1, 1); gtk_grid_attach_next_to(GTK_GRID(self->widget), bat, label, GTK_POS_RIGHT, 2, 1); // x/y offset g->x_offset = dt_bauhaus_slider_new_with_range(self, -1.0, 1.0, 0.001, p->xoffset, 3); dt_bauhaus_slider_set_format(g->x_offset, "%.3f"); dt_bauhaus_widget_set_label(g->x_offset, NULL, _("x offset")); g->y_offset = dt_bauhaus_slider_new_with_range(self, -1.0, 1.0, 0.001, p->yoffset, 3); dt_bauhaus_slider_set_format(g->y_offset, "%.3f"); dt_bauhaus_widget_set_label(g->y_offset, NULL, _("y offset")); gtk_grid_attach(GTK_GRID(self->widget), g->x_offset, 0, line++, 3, 1); gtk_grid_attach(GTK_GRID(self->widget), g->y_offset, 0, line++, 3, 1); // Let's add some tooltips and hook up some signals... gtk_widget_set_tooltip_text(g->opacity, _("the opacity of the watermark")); gtk_widget_set_tooltip_text(g->scale, _("the scale of the watermark")); gtk_widget_set_tooltip_text(g->rotate, _("the rotation of the watermark")); g_signal_connect(G_OBJECT(g->opacity), "value-changed", G_CALLBACK(opacity_callback), self); g_signal_connect(G_OBJECT(g->scale), "value-changed", G_CALLBACK(scale_callback), self); g_signal_connect(G_OBJECT(g->rotate), "value-changed", G_CALLBACK(rotate_callback), self); g_signal_connect(G_OBJECT(g->x_offset), "value-changed", G_CALLBACK(xoffset_callback), self); g_signal_connect(G_OBJECT(g->y_offset), "value-changed", G_CALLBACK(yoffset_callback), self); g_signal_connect(G_OBJECT(g->refresh), "clicked", G_CALLBACK(refresh_callback), self); refresh_watermarks(self); g_signal_connect(G_OBJECT(g->watermarks), "value-changed", G_CALLBACK(watermark_callback), self); g_signal_connect(G_OBJECT(g->sizeto), "value-changed", G_CALLBACK(sizeto_callback), self); g_signal_connect(G_OBJECT(g->text), "changed", G_CALLBACK(text_callback), self); g_signal_connect(G_OBJECT(g->colorpick), "color-set", G_CALLBACK(colorpick_color_set), self); g_signal_connect(G_OBJECT(g->fontsel), "font-set", G_CALLBACK(fontsel_callback), self); } void gui_cleanup(struct dt_iop_module_t *self) { free(self->gui_data); self->gui_data = NULL; }
int dt_lua_init_configuration(lua_State *L) { char tmp_path[PATH_MAX] = { 0 }; dt_lua_push_darktable_lib(L); dt_lua_goto_subtable(L, "configuration"); // build the table containing the configuration info lua_pushstring(L, "tmp_dir"); dt_loc_get_tmp_dir(tmp_path, sizeof(tmp_path)); lua_pushstring(L, tmp_path); lua_settable(L, -3); lua_pushstring(L, "config_dir"); dt_loc_get_user_config_dir(tmp_path, sizeof(tmp_path)); lua_pushstring(L, tmp_path); lua_settable(L, -3); lua_pushstring(L, "cache_dir"); dt_loc_get_user_cache_dir(tmp_path, sizeof(tmp_path)); lua_pushstring(L, tmp_path); lua_settable(L, -3); lua_pushstring(L, "version"); lua_pushstring(L, darktable_package_version); lua_settable(L, -3); lua_pushstring(L, "verbose"); lua_pushboolean(L, darktable.unmuted & DT_DEBUG_LUA); lua_settable(L, -3); lua_pushstring(L, "has_gui"); lua_pushboolean(L, darktable.gui != NULL); lua_settable(L, -3); lua_pushstring(L, "api_version_major"); lua_pushinteger(L, LUA_API_VERSION_MAJOR); lua_settable(L, -3); lua_pushstring(L, "api_version_minor"); lua_pushinteger(L, LUA_API_VERSION_MINOR); lua_settable(L, -3); lua_pushstring(L, "api_version_patch"); lua_pushinteger(L, LUA_API_VERSION_PATCH); lua_settable(L, -3); lua_pushstring(L, "api_version_suffix"); lua_pushstring(L, LUA_API_VERSION_SUFFIX); lua_settable(L, -3); lua_pushstring(L, "api_version_string"); if(LUA_API_VERSION_SUFFIX[0] == '\0') { lua_pushfstring(L, "%d.%d.%d", LUA_API_VERSION_MAJOR, LUA_API_VERSION_MINOR, LUA_API_VERSION_PATCH); } else { lua_pushfstring(L, "%d.%d.%d-%s", LUA_API_VERSION_MAJOR, LUA_API_VERSION_MINOR, LUA_API_VERSION_PATCH, LUA_API_VERSION_SUFFIX); } lua_settable(L, -3); lua_pushstring(L, "check_version"); lua_pushcfunction(L, check_version); lua_settable(L, -3); luaA_enum(L, lua_os_type); luaA_enum_value_name(L, lua_os_type, os_windows, "windows"); luaA_enum_value_name(L, lua_os_type, os_macos, "macos"); luaA_enum_value_name(L, lua_os_type, os_linux, "linux"); luaA_enum_value_name(L, lua_os_type, os_unix, "unix"); lua_pushstring(L, "running_os"); luaA_push(L, lua_os_type, &cur_os); lua_settable(L, -3); lua_pop(L, 1); // remove the configuration table from the stack return 0; }
static gchar * _watermark_get_svgdoc( dt_iop_module_t *self, dt_iop_watermark_data_t *data, const dt_image_t *image) { gsize length; gchar *svgdoc=NULL; gchar configdir[DT_MAX_PATH_LEN]; gchar datadir[DT_MAX_PATH_LEN]; gchar *filename; dt_loc_get_datadir(datadir, DT_MAX_PATH_LEN); dt_loc_get_user_config_dir(configdir, DT_MAX_PATH_LEN); g_strlcat(datadir,"/watermarks/", DT_MAX_PATH_LEN); g_strlcat(configdir,"/watermarks/", DT_MAX_PATH_LEN); g_strlcat(datadir,data->filename, DT_MAX_PATH_LEN); g_strlcat(configdir,data->filename, DT_MAX_PATH_LEN); if (g_file_test(configdir,G_FILE_TEST_EXISTS)) filename=configdir; else if (g_file_test(datadir,G_FILE_TEST_EXISTS)) filename=datadir; else return NULL; gchar *svgdata=NULL; char datetime[200]; // EXIF datetime struct tm tt_exif = {0}; if(sscanf(image->exif_datetime_taken,"%d:%d:%d %d:%d:%d", &tt_exif.tm_year, &tt_exif.tm_mon, &tt_exif.tm_mday, &tt_exif.tm_hour, &tt_exif.tm_min, &tt_exif.tm_sec ) == 6 ) { tt_exif.tm_year-=1900; tt_exif.tm_mon--; } // Current datetime struct tm tt_cur = {0}; time_t t = time(NULL); (void)localtime_r(&t, &tt_cur); if( g_file_get_contents( filename, &svgdata, &length, NULL) ) { // File is loaded lets substitute strings if found... // Darktable internal svgdoc = _string_substitute(svgdata,"$(DARKTABLE.NAME)",PACKAGE_NAME); if( svgdoc != svgdata ) { g_free(svgdata); svgdata = svgdoc; } svgdoc = _string_substitute(svgdata,"$(DARKTABLE.VERSION)",PACKAGE_VERSION); if( svgdoc != svgdata ) { g_free(svgdata); svgdata = svgdoc; } // Current image ID gchar buffer[1024]; g_snprintf(buffer,1024,"%d",image->id); svgdoc = _string_substitute(svgdata,"$(IMAGE.ID)",buffer); if( svgdoc != svgdata ) { g_free(svgdata); svgdata = svgdoc; } // Current image dt_image_print_exif(image,buffer,1024); svgdoc = _string_substitute(svgdata,"$(IMAGE.EXIF)",buffer); if( svgdoc != svgdata ) { g_free(svgdata); svgdata = svgdoc; } // Image exif // EXIF date svgdoc = _string_substitute(svgdata,"$(EXIF.DATE)",image->exif_datetime_taken); if( svgdoc != svgdata ) { g_free(svgdata); svgdata = svgdoc; } // $(EXIF.DATE.SECOND) -- 00..60 strftime(datetime, sizeof(datetime), "%S", &tt_exif); svgdoc = _string_substitute(svgdata,"$(EXIF.DATE.SECOND)",datetime); if( svgdoc != svgdata ) { g_free(svgdata); svgdata = svgdoc; } // $(EXIF.DATE.MINUTE) -- 00..59 strftime(datetime, sizeof(datetime), "%M", &tt_exif); svgdoc = _string_substitute(svgdata,"$(EXIF.DATE.MINUTE)",datetime); if( svgdoc != svgdata ) { g_free(svgdata); svgdata = svgdoc; } // $(EXIF.DATE.HOUR) -- 00..23 strftime(datetime, sizeof(datetime), "%H", &tt_exif); svgdoc = _string_substitute(svgdata,"$(EXIF.DATE.HOUR)",datetime); if( svgdoc != svgdata ) { g_free(svgdata); svgdata = svgdoc; } // $(EXIF.DATE.HOUR_AMPM) -- 01..12 strftime(datetime, sizeof(datetime), "%I %p", &tt_exif); svgdoc = _string_substitute(svgdata,"$(EXIF.DATE.HOUR_AMPM)",datetime); if( svgdoc != svgdata ) { g_free(svgdata); svgdata = svgdoc; } // $(EXIF.DATE.DAY) -- 01..31 strftime(datetime, sizeof(datetime), "%d", &tt_exif); svgdoc = _string_substitute(svgdata,"$(EXIF.DATE.DAY)",datetime); if( svgdoc != svgdata ) { g_free(svgdata); svgdata = svgdoc; } // $(EXIF.DATE.MONTH) -- 01..12 strftime(datetime, sizeof(datetime), "%m", &tt_exif); svgdoc = _string_substitute(svgdata,"$(EXIF.DATE.MONTH)",datetime); if( svgdoc != svgdata ) { g_free(svgdata); svgdata = svgdoc; } // $(EXIF.DATE.SHORT_MONTH) -- Jan, Feb, .., Dec, localized strftime(datetime, sizeof(datetime), "%b", &tt_exif); svgdoc = _string_substitute(svgdata,"$(EXIF.DATE.SHORT_MONTH)",datetime); if( svgdoc != svgdata ) { g_free(svgdata); svgdata = svgdoc; } // $(EXIF.DATE.LONG_MONTH) -- January, February, .., December, localized strftime(datetime, sizeof(datetime), "%B", &tt_exif); svgdoc = _string_substitute(svgdata,"$(EXIF.DATE.LONG_MONTH)",datetime); if( svgdoc != svgdata ) { g_free(svgdata); svgdata = svgdoc; } // $(EXIF.DATE.SHORT_YEAR) -- 12 strftime(datetime, sizeof(datetime), "%y", &tt_exif); svgdoc = _string_substitute(svgdata,"$(EXIF.DATE.SHORT_YEAR)",datetime); if( svgdoc != svgdata ) { g_free(svgdata); svgdata = svgdoc; } // $(EXIF.DATE.LONG_YEAR) -- 2012 strftime(datetime, sizeof(datetime), "%Y", &tt_exif); svgdoc = _string_substitute(svgdata,"$(EXIF.DATE.LONG_YEAR)",datetime); if( svgdoc != svgdata ) { g_free(svgdata); svgdata = svgdoc; } // Current date // $(DATE) -- YYYY: dt_gettime_t(datetime, t); svgdoc = _string_substitute(svgdata,"$(DATE)",datetime); if( svgdoc != svgdata ) { g_free(svgdata); svgdata = svgdoc; } // $(DATE.SECOND) -- 00..60 strftime(datetime, sizeof(datetime), "%S", &tt_cur); svgdoc = _string_substitute(svgdata,"$(DATE.SECOND)",datetime); if( svgdoc != svgdata ) { g_free(svgdata); svgdata = svgdoc; } // $(DATE.MINUTE) -- 00..59 strftime(datetime, sizeof(datetime), "%M", &tt_cur); svgdoc = _string_substitute(svgdata,"$(DATE.MINUTE)",datetime); if( svgdoc != svgdata ) { g_free(svgdata); svgdata = svgdoc; } // $(DATE.HOUR) -- 00..23 strftime(datetime, sizeof(datetime), "%H", &tt_cur); svgdoc = _string_substitute(svgdata,"$(DATE.HOUR)",datetime); if( svgdoc != svgdata ) { g_free(svgdata); svgdata = svgdoc; } // $(DATE.HOUR_AMPM) -- 01..12 strftime(datetime, sizeof(datetime), "%I %p", &tt_cur); svgdoc = _string_substitute(svgdata,"$(DATE.HOUR_AMPM)",datetime); if( svgdoc != svgdata ) { g_free(svgdata); svgdata = svgdoc; } // $(DATE.DAY) -- 01..31 strftime(datetime, sizeof(datetime), "%d", &tt_cur); svgdoc = _string_substitute(svgdata,"$(DATE.DAY)",datetime); if( svgdoc != svgdata ) { g_free(svgdata); svgdata = svgdoc; } // $(DATE.MONTH) -- 01..12 strftime(datetime, sizeof(datetime), "%m", &tt_cur); svgdoc = _string_substitute(svgdata,"$(DATE.MONTH)",datetime); if( svgdoc != svgdata ) { g_free(svgdata); svgdata = svgdoc; } // $(DATE.SHORT_MONTH) -- Jan, Feb, .., Dec, localized strftime(datetime, sizeof(datetime), "%b", &tt_cur); svgdoc = _string_substitute(svgdata,"$(DATE.SHORT_MONTH)",datetime); if( svgdoc != svgdata ) { g_free(svgdata); svgdata = svgdoc; } // $(DATE.LONG_MONTH) -- January, February, .., December, localized strftime(datetime, sizeof(datetime), "%B", &tt_cur); svgdoc = _string_substitute(svgdata,"$(DATE.LONG_MONTH)",datetime); if( svgdoc != svgdata ) { g_free(svgdata); svgdata = svgdoc; } // $(DATE.SHORT_YEAR) -- 12 strftime(datetime, sizeof(datetime), "%y", &tt_cur); svgdoc = _string_substitute(svgdata,"$(DATE.SHORT_YEAR)",datetime); if( svgdoc != svgdata ) { g_free(svgdata); svgdata = svgdoc; } // $(DATE.LONG_YEAR) -- 2012 strftime(datetime, sizeof(datetime), "%Y", &tt_cur); svgdoc = _string_substitute(svgdata,"$(DATE.LONG_YEAR)",datetime); if( svgdoc != svgdata ) { g_free(svgdata); svgdata = svgdoc; } svgdoc = _string_substitute(svgdata,"$(EXIF.MAKER)",image->exif_maker); if( svgdoc != svgdata ) { g_free(svgdata); svgdata = svgdoc; } svgdoc = _string_substitute(svgdata,"$(EXIF.MODEL)",image->exif_model); if( svgdoc != svgdata ) { g_free(svgdata); svgdata = svgdoc; } svgdoc = _string_substitute(svgdata,"$(EXIF.LENS)",image->exif_lens); if( svgdoc != svgdata ) { g_free(svgdata); svgdata = svgdoc; } svgdoc = _string_substitute(svgdata,"$(IMAGE.FILENAME)",image->filename); if( svgdoc != svgdata ) { g_free(svgdata); svgdata = svgdoc; } // TODO: auto generate that code? GList * res; res = dt_metadata_get(image->id, "Xmp.dc.creator", NULL); svgdoc = _string_substitute(svgdata,"$(Xmp.dc.creator)",(res?res->data:"")); if( svgdoc != svgdata ) { g_free(svgdata); svgdata = svgdoc; } if( res ) { g_free(res->data); g_list_free(res); } res = dt_metadata_get(image->id, "Xmp.dc.publisher", NULL); svgdoc = _string_substitute(svgdata,"$(Xmp.dc.publisher)",(res?res->data:"")); if( svgdoc != svgdata ) { g_free(svgdata); svgdata = svgdoc; } if( res ) { g_free(res->data); g_list_free(res); } res = dt_metadata_get(image->id, "Xmp.dc.title", NULL); svgdoc = _string_substitute(svgdata,"$(Xmp.dc.title)",(res?res->data:"")); if( svgdoc != svgdata ) { g_free(svgdata); svgdata = svgdoc; } if( res ) { g_free(res->data); g_list_free(res); } res = dt_metadata_get(image->id, "Xmp.dc.description", NULL); svgdoc = _string_substitute(svgdata,"$(Xmp.dc.description)",(res?res->data:"")); if( svgdoc != svgdata ) { g_free(svgdata); svgdata = svgdoc; } if( res ) { g_free(res->data); g_list_free(res); } res = dt_metadata_get(image->id, "Xmp.dc.rights", NULL); svgdoc = _string_substitute(svgdata,"$(Xmp.dc.rights)",(res?res->data:"")); if( svgdoc != svgdata ) { g_free(svgdata); svgdata = svgdoc; } if( res ) { g_free(res->data); g_list_free(res); } } return svgdoc; }
void dt_styles_update (const char *name, const char *newname, const char *newdescription, GList *filter, int imgid, GList *update) { sqlite3_stmt *stmt; int id=0; gchar *desc = NULL; id = dt_styles_get_id_by_name(name); if(id == 0) return; desc = dt_styles_get_description (name); if ((g_strcmp0(name, newname)) || (g_strcmp0(desc, newdescription))) { DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "UPDATE styles SET name=?1, description=?2 WHERE id=?3", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 1, newname, strlen (newname), SQLITE_STATIC); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 2, newdescription, strlen (newdescription), SQLITE_STATIC); DT_DEBUG_SQLITE3_BIND_INT(stmt, 3, id); sqlite3_step(stmt); sqlite3_finalize(stmt); } if (filter) { GList *list=filter; char tmp[64]; char include[2048] = {0}; g_strlcat(include,"num not in (", 2048); do { if(list!=g_list_first(list)) g_strlcat(include, ",", 2048); sprintf(tmp, "%d", GPOINTER_TO_INT(list->data)); g_strlcat(include, tmp, 2048); } while ((list=g_list_next(list))); g_strlcat(include,")", 2048); char query[4096]= {0}; sprintf(query,"delete from style_items where styleid=?1 and %s", include); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), query, -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); sqlite3_step(stmt); sqlite3_finalize(stmt); } _dt_style_update_from_image(id,imgid,filter,update); _dt_style_cleanup_multi_instance(id); /* backup style to disk */ char stylesdir[1024]; dt_loc_get_user_config_dir(stylesdir, 1024); g_strlcat(stylesdir,"/styles",1024); g_mkdir_with_parents(stylesdir,00755); dt_styles_save_to_file(newname,stylesdir,TRUE); /* delete old accelerator and create a new one */ //TODO: should better use dt_accel_rename_global() to keep the old accel_key untouched, but it seems to be buggy if (g_strcmp0(name, newname)) { char tmp_accel[1024]; snprintf(tmp_accel, 1024, C_("accel", "styles/apply %s"), name); dt_accel_deregister_global(tmp_accel); gchar* tmp_name = g_strdup(newname); // freed by _destroy_style_shortcut_callback snprintf(tmp_accel, 1024, C_("accel", "styles/apply %s"), newname); dt_accel_register_global( tmp_accel, 0, 0); GClosure *closure; closure = g_cclosure_new( G_CALLBACK(_apply_style_shortcut_callback), tmp_name, _destroy_style_shortcut_callback); dt_accel_connect_global(tmp_accel, closure); } g_free(desc); }
void dt_styles_create_from_style(const char *name, const char *newname, const char *description, GList *filter, int imgid, GList *update) { sqlite3_stmt *stmt; int id = 0; int oldid = 0; oldid = dt_styles_get_id_by_name(name); if(oldid == 0) return; /* create the style header */ if(!dt_styles_create_style_header(newname, description)) return; if((id = dt_styles_get_id_by_name(newname)) != 0) { if(filter) { GList *list = filter; char tmp[64]; char include[2048] = { 0 }; g_strlcat(include, "num IN (", sizeof(include)); do { if(list != g_list_first(list)) g_strlcat(include, ",", sizeof(include)); snprintf(tmp, sizeof(tmp), "%d", GPOINTER_TO_INT(list->data)); g_strlcat(include, tmp, sizeof(include)); } while((list = g_list_next(list))); g_strlcat(include, ")", sizeof(include)); char query[4096] = { 0 }; snprintf(query, sizeof(query), "INSERT INTO data.style_items " "(styleid,num,module,operation,op_params,enabled,blendop_params,blendop_" "version,multi_priority,multi_name) SELECT ?1, " "num,module,operation,op_params,enabled,blendop_params,blendop_version," "multi_priority,multi_name FROM data.style_items WHERE styleid=?2 AND %s", include); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), query, -1, &stmt, NULL); } else DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "INSERT INTO data.style_items " "(styleid,num,module,operation,op_params,enabled,blendop_params,blendop_" "version,multi_priority,multi_name) SELECT ?1, " "num,module,operation,op_params,enabled,blendop_params,blendop_version," "multi_priority,multi_name FROM data.style_items WHERE styleid=?2", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, oldid); sqlite3_step(stmt); sqlite3_finalize(stmt); /* insert items from imgid if defined */ _dt_style_update_from_image(id, imgid, filter, update); _dt_style_cleanup_multi_instance(id); /* backup style to disk */ char stylesdir[PATH_MAX] = { 0 }; dt_loc_get_user_config_dir(stylesdir, sizeof(stylesdir)); g_strlcat(stylesdir, "/styles", sizeof(stylesdir)); g_mkdir_with_parents(stylesdir, 00755); dt_styles_save_to_file(newname, stylesdir, FALSE); char tmp_accel[1024]; gchar *tmp_name = g_strdup(newname); // freed by _destroy_style_shortcut_callback snprintf(tmp_accel, sizeof(tmp_accel), C_("accel", "styles/apply %s"), newname); dt_accel_register_global(tmp_accel, 0, 0); GClosure *closure; closure = g_cclosure_new(G_CALLBACK(_apply_style_shortcut_callback), tmp_name, _destroy_style_shortcut_callback); dt_accel_connect_global(tmp_accel, closure); dt_control_log(_("style named '%s' successfully created"), newname); dt_control_signal_raise(darktable.signals, DT_SIGNAL_STYLE_CHANGED); } }
int dt_init(int argc, char *argv[], const int init_gui,lua_State *L) { #ifndef __WIN32__ if(getuid() == 0 || geteuid() == 0) printf("WARNING: either your user id or the effective user id are 0. are you running darktable as root?\n"); #endif // make everything go a lot faster. _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); #if !defined __APPLE__ && !defined __WIN32__ _dt_sigsegv_old_handler = signal(SIGSEGV,&_dt_sigsegv_handler); #endif #ifndef __GNUC_PREREQ // on OSX, gcc-4.6 and clang chokes if this is not here. #if defined __GNUC__ && defined __GNUC_MINOR__ # define __GNUC_PREREQ(maj, min) \ ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) #else # define __GNUC_PREREQ(maj, min) 0 #endif #endif #ifndef __has_builtin // http://clang.llvm.org/docs/LanguageExtensions.html#feature-checking-macros #define __has_builtin(x) false #endif #ifndef __SSE3__ #error "Unfortunately we depend on SSE3 instructions at this time." #error "Please contribute a backport patch (or buy a newer processor)." #else #if (__GNUC_PREREQ(4,8) || __has_builtin(__builtin_cpu_supports)) //FIXME: check will work only in GCC 4.8+ !!! implement manual cpuid check !!! //NOTE: _may_i_use_cpu_feature() looks better, but only avaliable in ICC if (!__builtin_cpu_supports("sse3")) { fprintf(stderr, "[dt_init] unfortunately we depend on SSE3 instructions at this time.\n"); fprintf(stderr, "[dt_init] please contribute a backport patch (or buy a newer processor).\n"); return 1; } #else //FIXME: no way to check for SSE3 in runtime, implement manual cpuid check !!! #endif #endif #ifdef M_MMAP_THRESHOLD mallopt(M_MMAP_THRESHOLD,128*1024) ; /* use mmap() for large allocations */ #endif // we have to have our share dir in XDG_DATA_DIRS, // otherwise GTK+ won't find our logo for the about screen (and maybe other things) { const gchar *xdg_data_dirs = g_getenv("XDG_DATA_DIRS"); gchar *new_xdg_data_dirs = NULL; gboolean set_env = TRUE; if(xdg_data_dirs != NULL && *xdg_data_dirs != '\0') { // check if DARKTABLE_SHAREDIR is already in there gboolean found = FALSE; gchar **tokens = g_strsplit(xdg_data_dirs, ":", 0); // xdg_data_dirs is neither NULL nor empty => tokens != NULL for(char **iter = tokens; *iter != NULL; iter++) if(!strcmp(DARKTABLE_SHAREDIR, *iter)) { found = TRUE; break; } g_strfreev(tokens); if(found) set_env = FALSE; else new_xdg_data_dirs = g_strjoin(":", DARKTABLE_SHAREDIR, xdg_data_dirs, NULL); } else { // see http://standards.freedesktop.org/basedir-spec/latest/ar01s03.html for a reason to use those as a default if(!g_strcmp0(DARKTABLE_SHAREDIR, "/usr/local/share") || !g_strcmp0(DARKTABLE_SHAREDIR, "/usr/local/share/") || !g_strcmp0(DARKTABLE_SHAREDIR, "/usr/share") || !g_strcmp0(DARKTABLE_SHAREDIR, "/usr/share/")) new_xdg_data_dirs = g_strdup("/usr/local/share/:/usr/share/"); else new_xdg_data_dirs = g_strdup_printf("%s:/usr/local/share/:/usr/share/", DARKTABLE_SHAREDIR); } if(set_env) g_setenv("XDG_DATA_DIRS", new_xdg_data_dirs, 1); g_free(new_xdg_data_dirs); } setlocale(LC_ALL, ""); bindtextdomain (GETTEXT_PACKAGE, DARKTABLE_LOCALEDIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); // init all pointers to 0: memset(&darktable, 0, sizeof(darktable_t)); darktable.progname = argv[0]; // database gchar *dbfilename_from_command = NULL; char *datadir_from_command = NULL; char *moduledir_from_command = NULL; char *tmpdir_from_command = NULL; char *configdir_from_command = NULL; char *cachedir_from_command = NULL; #ifdef USE_LUA char *lua_command = NULL; #endif darktable.num_openmp_threads = 1; #ifdef _OPENMP darktable.num_openmp_threads = omp_get_num_procs(); #endif darktable.unmuted = 0; GSList *images_to_load = NULL, *config_override = NULL; for(int k=1; k<argc; k++) { if(argv[k][0] == '-') { if(!strcmp(argv[k], "--help")) { return usage(argv[0]); } if(!strcmp(argv[k], "-h")) { return usage(argv[0]); } else if(!strcmp(argv[k], "--version")) { printf("this is "PACKAGE_STRING"\ncopyright (c) 2009-2014 johannes hanika\n"PACKAGE_BUGREPORT"\n" #ifdef _OPENMP "OpenMP support enabled\n" #else "OpenMP support disabled\n" #endif ); return 1; } else if(!strcmp(argv[k], "--library")) { dbfilename_from_command = argv[++k]; } else if(!strcmp(argv[k], "--datadir")) { datadir_from_command = argv[++k]; } else if(!strcmp(argv[k], "--moduledir")) { moduledir_from_command = argv[++k]; } else if(!strcmp(argv[k], "--tmpdir")) { tmpdir_from_command = argv[++k]; } else if(!strcmp(argv[k], "--configdir")) { configdir_from_command = argv[++k]; } else if(!strcmp(argv[k], "--cachedir")) { cachedir_from_command = argv[++k]; } else if(!strcmp(argv[k], "--localedir")) { bindtextdomain (GETTEXT_PACKAGE, argv[++k]); } else if(argv[k][1] == 'd' && argc > k+1) { if(!strcmp(argv[k+1], "all")) darktable.unmuted = 0xffffffff; // enable all debug information else if(!strcmp(argv[k+1], "cache")) darktable.unmuted |= DT_DEBUG_CACHE; // enable debugging for lib/film/cache module else if(!strcmp(argv[k+1], "control")) darktable.unmuted |= DT_DEBUG_CONTROL; // enable debugging for scheduler module else if(!strcmp(argv[k+1], "dev")) darktable.unmuted |= DT_DEBUG_DEV; // develop module else if(!strcmp(argv[k+1], "fswatch")) darktable.unmuted |= DT_DEBUG_FSWATCH; // fswatch module else if(!strcmp(argv[k+1], "input")) darktable.unmuted |= DT_DEBUG_INPUT; // input devices else if(!strcmp(argv[k+1], "camctl")) darktable.unmuted |= DT_DEBUG_CAMCTL; // camera control module else if(!strcmp(argv[k+1], "perf")) darktable.unmuted |= DT_DEBUG_PERF; // performance measurements else if(!strcmp(argv[k+1], "pwstorage")) darktable.unmuted |= DT_DEBUG_PWSTORAGE; // pwstorage module else if(!strcmp(argv[k+1], "opencl")) darktable.unmuted |= DT_DEBUG_OPENCL; // gpu accel via opencl else if(!strcmp(argv[k+1], "sql")) darktable.unmuted |= DT_DEBUG_SQL; // SQLite3 queries else if(!strcmp(argv[k+1], "memory")) darktable.unmuted |= DT_DEBUG_MEMORY; // some stats on mem usage now and then. else if(!strcmp(argv[k+1], "lighttable")) darktable.unmuted |= DT_DEBUG_LIGHTTABLE; // lighttable related stuff. else if(!strcmp(argv[k+1], "nan")) darktable.unmuted |= DT_DEBUG_NAN; // check for NANs when processing the pipe. else if(!strcmp(argv[k+1], "masks")) darktable.unmuted |= DT_DEBUG_MASKS; // masks related stuff. else if(!strcmp(argv[k+1], "lua")) darktable.unmuted |= DT_DEBUG_LUA; // lua errors are reported on console else return usage(argv[0]); k ++; } else if(argv[k][1] == 't' && argc > k+1) { darktable.num_openmp_threads = CLAMP(atol(argv[k+1]), 1, 100); printf("[dt_init] using %d threads for openmp parallel sections\n", darktable.num_openmp_threads); k ++; } else if(!strcmp(argv[k], "--conf")) { gchar *keyval = g_strdup(argv[++k]), *c = keyval; gchar *end = keyval + strlen(keyval); while(*c != '=' && c < end) c++; if(*c == '=' && *(c+1) != '\0') { *c++ = '\0'; dt_conf_string_entry_t *entry = (dt_conf_string_entry_t*)g_malloc(sizeof(dt_conf_string_entry_t)); entry->key = g_strdup(keyval); entry->value = g_strdup(c); config_override = g_slist_append(config_override, entry); } g_free(keyval); } else if(!strcmp(argv[k], "--luacmd")) { #ifdef USE_LUA lua_command = argv[++k]; #else ++k; #endif } } #ifndef MAC_INTEGRATION else { images_to_load = g_slist_append(images_to_load, argv[k]); } #endif } if(darktable.unmuted & DT_DEBUG_MEMORY) { fprintf(stderr, "[memory] at startup\n"); dt_print_mem_usage(); } #ifdef _OPENMP omp_set_num_threads(darktable.num_openmp_threads); #endif dt_loc_init_datadir(datadir_from_command); dt_loc_init_plugindir(moduledir_from_command); if(dt_loc_init_tmp_dir(tmpdir_from_command)) { printf(_("ERROR : invalid temporary directory : %s\n"),darktable.tmpdir); return usage(argv[0]); } dt_loc_init_user_config_dir(configdir_from_command); dt_loc_init_user_cache_dir(cachedir_from_command); #if !GLIB_CHECK_VERSION(2, 35, 0) g_type_init(); #endif // does not work, as gtk is not inited yet. // even if it were, it's a super bad idea to invoke gtk stuff from // a signal handler. /* check cput caps */ // dt_check_cpu(argc,argv); #ifdef HAVE_GEGL char geglpath[PATH_MAX]; char datadir[PATH_MAX]; dt_loc_get_datadir(datadir, sizeof(datadir)); snprintf(geglpath, sizeof(geglpath), "%s/gegl:/usr/lib/gegl-0.0", datadir); (void)setenv("GEGL_PATH", geglpath, 1); gegl_init(&argc, &argv); #endif #ifdef USE_LUA dt_lua_init_early(L); #endif // thread-safe init: dt_exif_init(); char datadir[PATH_MAX]; dt_loc_get_user_config_dir (datadir, sizeof(datadir)); char filename[PATH_MAX]; snprintf(filename, sizeof(filename), "%s/darktablerc", datadir); // initialize the config backend. this needs to be done first... darktable.conf = (dt_conf_t *)calloc(1, sizeof(dt_conf_t)); dt_conf_init(darktable.conf, filename, config_override); g_slist_free_full(config_override, g_free); // set the interface language const gchar* lang = dt_conf_get_string("ui_last/gui_language"); // we may not g_free 'lang' since it is owned by setlocale afterwards if(lang != NULL && lang[0] != '\0') { if(setlocale(LC_ALL, lang) != NULL) gtk_disable_setlocale(); } // initialize the database darktable.db = dt_database_init(dbfilename_from_command); if(darktable.db == NULL) { printf("ERROR : cannot open database\n"); return 1; } else if(!dt_database_get_lock_acquired(darktable.db)) { // send the images to the other instance via dbus if(images_to_load) { GSList *p = images_to_load; // get a connection! GDBusConnection *connection = g_bus_get_sync(G_BUS_TYPE_SESSION,NULL, NULL); while (p != NULL) { // make the filename absolute ... gchar *filename = dt_make_path_absolute((gchar*)p->data); if(filename == NULL) continue; // ... and send it to the running instance of darktable g_dbus_connection_call_sync(connection, "org.darktable.service", "/darktable", "org.darktable.service.Remote", "Open", g_variant_new ("(s)", filename), NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL); p = g_slist_next(p); g_free(filename); } g_slist_free(images_to_load); g_object_unref(connection); } return 1; } // Initialize the signal system darktable.signals = dt_control_signal_init(); // Make sure that the database and xmp files are in sync before starting the fswatch. // We need conf and db to be up and running for that which is the case here. // FIXME: is this also useful in non-gui mode? GList *changed_xmp_files = NULL; if(init_gui && dt_conf_get_bool("run_crawler_on_start")) { changed_xmp_files = dt_control_crawler_run(); } // Initialize the filesystem watcher darktable.fswatch=dt_fswatch_new(); #ifdef HAVE_GPHOTO2 // Initialize the camera control darktable.camctl=dt_camctl_new(); #endif // get max lighttable thumbnail size: darktable.thumbnail_width = CLAMPS(dt_conf_get_int("plugins/lighttable/thumbnail_width"), 200, 3000); darktable.thumbnail_height = CLAMPS(dt_conf_get_int("plugins/lighttable/thumbnail_height"), 200, 3000); // and make sure it can be mip-mapped all the way from mip4 to mip0 darktable.thumbnail_width /= 16; darktable.thumbnail_width *= 16; darktable.thumbnail_height /= 16; darktable.thumbnail_height *= 16; // Initialize the password storage engine darktable.pwstorage=dt_pwstorage_new(); // FIXME: move there into dt_database_t dt_pthread_mutex_init(&(darktable.db_insert), NULL); dt_pthread_mutex_init(&(darktable.plugin_threadsafe), NULL); dt_pthread_mutex_init(&(darktable.capabilities_threadsafe), NULL); darktable.control = (dt_control_t *)calloc(1, sizeof(dt_control_t)); if(init_gui) { dt_control_init(darktable.control); } else { if(dbfilename_from_command && !strcmp(dbfilename_from_command, ":memory:")) dt_gui_presets_init(); // init preset db schema. darktable.control->running = 0; darktable.control->accelerators = NULL; dt_pthread_mutex_init(&darktable.control->run_mutex, NULL); } // initialize collection query darktable.collection_listeners = NULL; darktable.collection = dt_collection_new(NULL); /* initialize selection */ darktable.selection = dt_selection_new(); /* capabilities set to NULL */ darktable.capabilities = NULL; #ifdef HAVE_GRAPHICSMAGICK /* GraphicsMagick init */ InitializeMagick(darktable.progname); #endif darktable.opencl = (dt_opencl_t *)calloc(1, sizeof(dt_opencl_t)); #ifdef HAVE_OPENCL dt_opencl_init(darktable.opencl, argc, argv); #endif darktable.blendop = (dt_blendop_t *)calloc(1, sizeof(dt_blendop_t)); dt_develop_blend_init(darktable.blendop); darktable.points = (dt_points_t *)calloc(1, sizeof(dt_points_t)); dt_points_init(darktable.points, dt_get_num_threads()); // must come before mipmap_cache, because that one will need to access // image dimensions stored in here: darktable.image_cache = (dt_image_cache_t *)calloc(1, sizeof(dt_image_cache_t)); dt_image_cache_init(darktable.image_cache); darktable.mipmap_cache = (dt_mipmap_cache_t *)calloc(1, sizeof(dt_mipmap_cache_t)); dt_mipmap_cache_init(darktable.mipmap_cache); // The GUI must be initialized before the views, because the init() // functions of the views depend on darktable.control->accels_* to register // their keyboard accelerators if(init_gui) { darktable.gui = (dt_gui_gtk_t *)calloc(1, sizeof(dt_gui_gtk_t)); if(dt_gui_gtk_init(darktable.gui, argc, argv)) return 1; dt_bauhaus_init(); } else darktable.gui = NULL; darktable.view_manager = (dt_view_manager_t *)calloc(1, sizeof(dt_view_manager_t)); dt_view_manager_init(darktable.view_manager); darktable.imageio = (dt_imageio_t *)calloc(1, sizeof(dt_imageio_t)); dt_imageio_init(darktable.imageio); // load the darkroom mode plugins once: dt_iop_load_modules_so(); if(init_gui) { darktable.lib = (dt_lib_t *)calloc(1, sizeof(dt_lib_t)); dt_lib_init(darktable.lib); dt_control_load_config(darktable.control); } if(init_gui) { // Loading the keybindings char keyfile[PATH_MAX]; // First dump the default keymapping snprintf(keyfile, sizeof(keyfile), "%s/keyboardrc_default", datadir); gtk_accel_map_save(keyfile); // Removing extraneous semi-colons from the default keymap strip_semicolons_from_keymap(keyfile); // Then load any modified keys if available snprintf(keyfile, sizeof(keyfile), "%s/keyboardrc", datadir); if(g_file_test(keyfile, G_FILE_TEST_EXISTS)) gtk_accel_map_load(keyfile); else gtk_accel_map_save(keyfile); // Save the default keymap if none is present // I doubt that connecting to dbus for darktable-cli makes sense darktable.dbus = dt_dbus_init(); // initialize undo struct darktable.undo = dt_undo_init(); // load image(s) specified on cmdline int id = 0; if(images_to_load) { // If only one image is listed, attempt to load it in darkroom gboolean load_in_dr = (g_slist_next(images_to_load) == NULL); GSList *p = images_to_load; while (p != NULL) { // don't put these function calls into MAX(), the macro will evaluate // it twice (and happily deadlock, in this particular case) int newid = dt_load_from_string((gchar*)p->data, load_in_dr); id = MAX(id, newid); p = g_slist_next(p); } if (!load_in_dr || id == 0) dt_ctl_switch_mode_to(DT_LIBRARY); g_slist_free(images_to_load); } else dt_ctl_switch_mode_to(DT_LIBRARY); } if(darktable.unmuted & DT_DEBUG_MEMORY) { fprintf(stderr, "[memory] after successful startup\n"); dt_print_mem_usage(); } dt_image_local_copy_synch(); /* init lua last, since it's user made stuff it must be in the real environment */ #ifdef USE_LUA dt_lua_init(darktable.lua_state.state,lua_command); #endif // last but not least construct the popup that asks the user about images whose xmp files are newer than the db entry if(init_gui && changed_xmp_files) { dt_control_crawler_show_image_list(changed_xmp_files); } return 0; }
dt_database_t *dt_database_init(char *alternative) { /* migrate default database location to new default */ _database_migrate_to_xdg_structure(); /* delete old mipmaps files */ _database_delete_mipmaps_files(); /* lets construct the db filename */ gchar * dbname = NULL; gchar dbfilename[DT_MAX_PATH_LEN] = {0}; gchar datadir[DT_MAX_PATH_LEN] = {0}; dt_loc_get_user_config_dir(datadir, DT_MAX_PATH_LEN); if ( alternative == NULL ) { dbname = dt_conf_get_string ("database"); if(!dbname) snprintf(dbfilename, DT_MAX_PATH_LEN, "%s/library.db", datadir); else if(dbname[0] != '/') snprintf(dbfilename, DT_MAX_PATH_LEN, "%s/%s", datadir, dbname); else snprintf(dbfilename, DT_MAX_PATH_LEN, "%s", dbname); } else { snprintf(dbfilename, DT_MAX_PATH_LEN, "%s", alternative); GFile *galternative = g_file_new_for_path(alternative); dbname = g_file_get_basename (galternative); g_object_unref(galternative); } /* create database */ dt_database_t *db = (dt_database_t *)g_malloc(sizeof(dt_database_t)); memset(db,0,sizeof(dt_database_t)); db->dbfilename = g_strdup(dbfilename); db->is_new_database = FALSE; db->lock_acquired = FALSE; /* having more than one instance of darktable using the same database is a bad idea */ /* try to get a lock for the database */ #ifdef __WIN32__ db->lock_acquired = TRUE; #else mode_t old_mode; int fd, lock_tries = 0; if(!strcmp(dbfilename, ":memory:")) { db->lock_acquired = TRUE; } else { db->lockfile = g_strconcat(dbfilename, ".lock", NULL); lock_again: lock_tries++; old_mode = umask(0); fd = open(db->lockfile, O_RDWR | O_CREAT | O_EXCL, 0666); umask(old_mode); if(fd >= 0) // the lockfile was successfully created - write our PID into it { gchar *pid = g_strdup_printf("%d", getpid()); if(write(fd, pid, strlen(pid)+1) > -1) db->lock_acquired = TRUE; close(fd); } else // the lockfile already exists - see if it's a stale one left over from a crashed instance { char buf[64]; memset(buf, 0, sizeof(buf)); fd = open(db->lockfile, O_RDWR | O_CREAT, 0666); if(fd >= 0) { if(read(fd, buf, sizeof(buf) - 1) > -1) { int other_pid = atoi(buf); if((kill(other_pid, 0) == -1) && errno == ESRCH) { // the other process seems to no longer exist. unlink the .lock file and try again unlink(db->lockfile); if(lock_tries < 5) goto lock_again; } } close(fd); } } } #endif if(!db->lock_acquired) { fprintf(stderr, "[init] database is locked, probably another process is already using it\n"); g_free(dbname); return db; } /* test if databasefile is available */ if(!g_file_test(dbfilename, G_FILE_TEST_IS_REGULAR)) db->is_new_database = TRUE; /* opening / creating database */ if(sqlite3_open(db->dbfilename, &db->handle)) { fprintf(stderr, "[init] could not find database "); if(dbname) fprintf(stderr, "`%s'!\n", dbname); else fprintf(stderr, "\n"); fprintf(stderr, "[init] maybe your %s/darktablerc is corrupt?\n",datadir); dt_loc_get_datadir(dbfilename, 512); fprintf(stderr, "[init] try `cp %s/darktablerc %s/darktablerc'\n", dbfilename,datadir); sqlite3_close(db->handle); g_free(dbname); g_free(db->lockfile); g_free(db); return NULL; } /* attach a memory database to db connection for use with temporary tables used during instance life time, which is discarded on exit. */ sqlite3_exec(db->handle, "attach database ':memory:' as memory",NULL,NULL,NULL); sqlite3_exec(db->handle, "PRAGMA synchronous = OFF", NULL, NULL, NULL); sqlite3_exec(db->handle, "PRAGMA journal_mode = MEMORY", NULL, NULL, NULL); sqlite3_exec(db->handle, "PRAGMA page_size = 32768", NULL, NULL, NULL); /* now that we got a functional database that is locked for us we can make sure that the schema is set up */ // does the db contain the new 'db_info' table? sqlite3_stmt *stmt; int rc = sqlite3_prepare_v2(db->handle, "select value from db_info where key = 'version'", -1, &stmt, NULL); if(rc == SQLITE_OK && sqlite3_step(stmt) == SQLITE_ROW) { // compare the version of the db with what is current for this executable const int db_version = sqlite3_column_int(stmt, 0); sqlite3_finalize(stmt); if(db_version < CURRENT_DATABASE_VERSION) { // older: upgrade if(!_upgrade_schema(db, db_version)) { // we couldn't upgrade the db for some reason. bail out. fprintf(stderr, "[init] database `%s' couldn't be upgraded from version %d to %d. aborting\n", dbname, db_version, CURRENT_DATABASE_VERSION); dt_database_destroy(db); db = NULL; goto error; } } else if(db_version > CURRENT_DATABASE_VERSION) { // newer: bail out. it's better than what we did before: delete everything fprintf(stderr, "[init] database version of `%s' is too new for this build of darktable. aborting\n", dbname); dt_database_destroy(db); db = NULL; goto error; } // else: the current version, do nothing } else { // does it contain the legacy 'settings' table? sqlite3_finalize(stmt); rc = sqlite3_prepare_v2(db->handle, "select settings from settings", -1, &stmt, NULL); if(rc == SQLITE_OK && sqlite3_step(stmt) == SQLITE_ROW) { // the old blob had the version as an int in the first place const void *set = sqlite3_column_blob(stmt, 0); const int db_version = *(int*)set; sqlite3_finalize(stmt); if(!_migrate_schema(db, db_version)) // bring the legacy layout to the first one known to our upgrade path ... { // we couldn't migrate the db for some reason. bail out. fprintf(stderr, "[init] database `%s' couldn't be migrated from the legacy version %d. aborting\n", dbname, db_version); dt_database_destroy(db); db = NULL; goto error; } if(!_upgrade_schema(db, 1)) // ... and upgrade it { // we couldn't upgrade the db for some reason. bail out. fprintf(stderr, "[init] database `%s' couldn't be upgraded from version 1 to %d. aborting\n", dbname, CURRENT_DATABASE_VERSION); dt_database_destroy(db); db = NULL; goto error; } } else { sqlite3_finalize(stmt); _create_schema(db); // a brand new db it seems } } // create the in-memory tables // temporary stuff for some ops, need this for some reason with newer sqlite3: DT_DEBUG_SQLITE3_EXEC(db->handle, "CREATE TABLE memory.color_labels_temp (imgid INTEGER PRIMARY KEY)", NULL, NULL, NULL); DT_DEBUG_SQLITE3_EXEC(db->handle, "CREATE TABLE memory.collected_images (rowid INTEGER PRIMARY KEY AUTOINCREMENT, imgid INTEGER)", NULL, NULL, NULL); DT_DEBUG_SQLITE3_EXEC(db->handle, "CREATE TABLE memory.tmp_selection (imgid INTEGER)", NULL, NULL, NULL); DT_DEBUG_SQLITE3_EXEC(db->handle, "CREATE TABLE memory.tagq (tmpid INTEGER PRIMARY KEY, id INTEGER)", NULL, NULL, NULL); DT_DEBUG_SQLITE3_EXEC(db->handle, "CREATE TABLE memory.taglist " "(tmpid INTEGER PRIMARY KEY, id INTEGER UNIQUE ON CONFLICT REPLACE, " "count INTEGER)", NULL, NULL, NULL); DT_DEBUG_SQLITE3_EXEC(db->handle, "CREATE TABLE memory.history (imgid INTEGER, num INTEGER, module INTEGER, " "operation VARCHAR(256) UNIQUE ON CONFLICT REPLACE, op_params BLOB, enabled INTEGER, " "blendop_params BLOB, blendop_version INTEGER, multi_priority INTEGER, multi_name VARCHAR(256))", NULL, NULL, NULL); DT_DEBUG_SQLITE3_EXEC(db->handle, "CREATE TABLE MEMORY.style_items (styleid INTEGER, num INTEGER, module INTEGER, " "operation VARCHAR(256), op_params BLOB, enabled INTEGER, " "blendop_params BLOB, blendop_version INTEGER, multi_priority INTEGER, multi_name VARCHAR(256))", NULL, NULL, NULL); // create a table legacy_presets with all the presets from pre-auto-apply-cleanup darktable. dt_legacy_presets_create(db); // drop table settings -- we don't want old versions of dt to drop our tables sqlite3_exec(db->handle, "drop table settings", NULL, NULL, NULL); error: g_free(dbname); return db; }
int dt_init(int argc, char *argv[], const gboolean init_gui, const gboolean load_data, lua_State *L) { double start_wtime = dt_get_wtime(); #ifndef __WIN32__ if(getuid() == 0 || geteuid() == 0) printf( "WARNING: either your user id or the effective user id are 0. are you running darktable as root?\n"); #endif #if defined(__SSE__) // make everything go a lot faster. _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); #endif dt_set_signal_handlers(); #include "is_supported_platform.h" int sse2_supported = 0; #ifdef HAVE_BUILTIN_CPU_SUPPORTS // NOTE: _may_i_use_cpu_feature() looks better, but only avaliable in ICC __builtin_cpu_init(); sse2_supported = __builtin_cpu_supports("sse2"); #else sse2_supported = dt_detect_cpu_features() & CPU_FLAG_SSE2; #endif if(!sse2_supported) { fprintf(stderr, "[dt_init] SSE2 instruction set is unavailable.\n"); fprintf(stderr, "[dt_init] expect a LOT of functionality to be broken. you have been warned.\n"); } #ifdef M_MMAP_THRESHOLD mallopt(M_MMAP_THRESHOLD, 128 * 1024); /* use mmap() for large allocations */ #endif // make sure that stack/frame limits are good (musl) dt_set_rlimits(); // we have to have our share dir in XDG_DATA_DIRS, // otherwise GTK+ won't find our logo for the about screen (and maybe other things) { const gchar *xdg_data_dirs = g_getenv("XDG_DATA_DIRS"); gchar *new_xdg_data_dirs = NULL; gboolean set_env = TRUE; if(xdg_data_dirs != NULL && *xdg_data_dirs != '\0') { // check if DARKTABLE_SHAREDIR is already in there gboolean found = FALSE; gchar **tokens = g_strsplit(xdg_data_dirs, G_SEARCHPATH_SEPARATOR_S, 0); // xdg_data_dirs is neither NULL nor empty => tokens != NULL for(char **iter = tokens; *iter != NULL; iter++) if(!strcmp(DARKTABLE_SHAREDIR, *iter)) { found = TRUE; break; } g_strfreev(tokens); if(found) set_env = FALSE; else new_xdg_data_dirs = g_strjoin(G_SEARCHPATH_SEPARATOR_S, DARKTABLE_SHAREDIR, xdg_data_dirs, NULL); } else { #ifndef _WIN32 // see http://standards.freedesktop.org/basedir-spec/latest/ar01s03.html for a reason to use those as a // default if(!g_strcmp0(DARKTABLE_SHAREDIR, "/usr/local/share") || !g_strcmp0(DARKTABLE_SHAREDIR, "/usr/local/share/") || !g_strcmp0(DARKTABLE_SHAREDIR, "/usr/share") || !g_strcmp0(DARKTABLE_SHAREDIR, "/usr/share/")) new_xdg_data_dirs = g_strdup("/usr/local/share/" G_SEARCHPATH_SEPARATOR_S "/usr/share/"); else new_xdg_data_dirs = g_strdup_printf("%s" G_SEARCHPATH_SEPARATOR_S "/usr/local/share/" G_SEARCHPATH_SEPARATOR_S "/usr/share/", DARKTABLE_SHAREDIR); #else set_env = FALSE; #endif } if(set_env) g_setenv("XDG_DATA_DIRS", new_xdg_data_dirs, 1); g_free(new_xdg_data_dirs); } setlocale(LC_ALL, ""); bindtextdomain(GETTEXT_PACKAGE, DARKTABLE_LOCALEDIR); bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); textdomain(GETTEXT_PACKAGE); // init all pointers to 0: memset(&darktable, 0, sizeof(darktable_t)); darktable.start_wtime = start_wtime; darktable.progname = argv[0]; // FIXME: move there into dt_database_t dt_pthread_mutex_init(&(darktable.db_insert), NULL); dt_pthread_mutex_init(&(darktable.plugin_threadsafe), NULL); dt_pthread_mutex_init(&(darktable.capabilities_threadsafe), NULL); darktable.control = (dt_control_t *)calloc(1, sizeof(dt_control_t)); // database char *dbfilename_from_command = NULL; char *noiseprofiles_from_command = NULL; char *datadir_from_command = NULL; char *moduledir_from_command = NULL; char *tmpdir_from_command = NULL; char *configdir_from_command = NULL; char *cachedir_from_command = NULL; #ifdef HAVE_OPENCL gboolean exclude_opencl = FALSE; gboolean print_statistics = strcmp(argv[0], "darktable-cltest"); #endif #ifdef USE_LUA char *lua_command = NULL; #endif darktable.num_openmp_threads = 1; #ifdef _OPENMP darktable.num_openmp_threads = omp_get_num_procs(); #endif darktable.unmuted = 0; GSList *config_override = NULL; for(int k = 1; k < argc; k++) { if(argv[k][0] == '-') { if(!strcmp(argv[k], "--help")) { return usage(argv[0]); } if(!strcmp(argv[k], "-h")) { return usage(argv[0]); } else if(!strcmp(argv[k], "--version")) { #ifdef USE_LUA const char *lua_api_version = strcmp(LUA_API_VERSION_SUFFIX, "") ? STR(LUA_API_VERSION_MAJOR) "." STR(LUA_API_VERSION_MINOR) "." STR(LUA_API_VERSION_PATCH) "-" LUA_API_VERSION_SUFFIX : STR(LUA_API_VERSION_MAJOR) "." STR(LUA_API_VERSION_MINOR) "." STR(LUA_API_VERSION_PATCH); #endif printf("this is %s\ncopyright (c) 2009-%s johannes hanika\n" PACKAGE_BUGREPORT "\n\ncompile options:\n" " bit depth is %s\n" #ifdef _DEBUG " debug build\n" #else " normal build\n" #endif #if defined(__SSE2__) && defined(__SSE__) " SSE2 optimized codepath enabled\n" #else " SSE2 optimized codepath disabled\n" #endif #ifdef _OPENMP " OpenMP support enabled\n" #else " OpenMP support disabled\n" #endif #ifdef HAVE_OPENCL " OpenCL support enabled\n" #else " OpenCL support disabled\n" #endif #ifdef USE_LUA " Lua support enabled, API version %s\n" #else " Lua support disabled\n" #endif #ifdef USE_COLORDGTK " Colord support enabled\n" #else " Colord support disabled\n" #endif #ifdef HAVE_GPHOTO2 " gPhoto2 support enabled\n" #else " gPhoto2 support disabled\n" #endif #ifdef HAVE_GRAPHICSMAGICK " GraphicsMagick support enabled\n" #else " GraphicsMagick support disabled\n" #endif #ifdef HAVE_OPENEXR " OpenEXR support enabled\n" #else " OpenEXR support disabled\n" #endif , darktable_package_string, darktable_last_commit_year, (sizeof(void *) == 8 ? "64 bit" : sizeof(void *) == 4 ? "32 bit" : "unknown") #if USE_LUA , lua_api_version #endif ); return 1; } else if(!strcmp(argv[k], "--library") && argc > k + 1) { dbfilename_from_command = argv[++k]; argv[k-1] = NULL; argv[k] = NULL; } else if(!strcmp(argv[k], "--datadir") && argc > k + 1) { datadir_from_command = argv[++k]; argv[k-1] = NULL; argv[k] = NULL; } else if(!strcmp(argv[k], "--moduledir") && argc > k + 1) { moduledir_from_command = argv[++k]; argv[k-1] = NULL; argv[k] = NULL; } else if(!strcmp(argv[k], "--tmpdir") && argc > k + 1) { tmpdir_from_command = argv[++k]; argv[k-1] = NULL; argv[k] = NULL; } else if(!strcmp(argv[k], "--configdir") && argc > k + 1) { configdir_from_command = argv[++k]; argv[k-1] = NULL; argv[k] = NULL; } else if(!strcmp(argv[k], "--cachedir") && argc > k + 1) { cachedir_from_command = argv[++k]; argv[k-1] = NULL; argv[k] = NULL; } else if(!strcmp(argv[k], "--localedir") && argc > k + 1) { bindtextdomain(GETTEXT_PACKAGE, argv[++k]); argv[k-1] = NULL; argv[k] = NULL; } else if(argv[k][1] == 'd' && argc > k + 1) { if(!strcmp(argv[k + 1], "all")) darktable.unmuted = 0xffffffff; // enable all debug information else if(!strcmp(argv[k + 1], "cache")) darktable.unmuted |= DT_DEBUG_CACHE; // enable debugging for lib/film/cache module else if(!strcmp(argv[k + 1], "control")) darktable.unmuted |= DT_DEBUG_CONTROL; // enable debugging for scheduler module else if(!strcmp(argv[k + 1], "dev")) darktable.unmuted |= DT_DEBUG_DEV; // develop module else if(!strcmp(argv[k + 1], "input")) darktable.unmuted |= DT_DEBUG_INPUT; // input devices else if(!strcmp(argv[k + 1], "camctl")) darktable.unmuted |= DT_DEBUG_CAMCTL; // camera control module else if(!strcmp(argv[k + 1], "perf")) darktable.unmuted |= DT_DEBUG_PERF; // performance measurements else if(!strcmp(argv[k + 1], "pwstorage")) darktable.unmuted |= DT_DEBUG_PWSTORAGE; // pwstorage module else if(!strcmp(argv[k + 1], "opencl")) darktable.unmuted |= DT_DEBUG_OPENCL; // gpu accel via opencl else if(!strcmp(argv[k + 1], "sql")) darktable.unmuted |= DT_DEBUG_SQL; // SQLite3 queries else if(!strcmp(argv[k + 1], "memory")) darktable.unmuted |= DT_DEBUG_MEMORY; // some stats on mem usage now and then. else if(!strcmp(argv[k + 1], "lighttable")) darktable.unmuted |= DT_DEBUG_LIGHTTABLE; // lighttable related stuff. else if(!strcmp(argv[k + 1], "nan")) darktable.unmuted |= DT_DEBUG_NAN; // check for NANs when processing the pipe. else if(!strcmp(argv[k + 1], "masks")) darktable.unmuted |= DT_DEBUG_MASKS; // masks related stuff. else if(!strcmp(argv[k + 1], "lua")) darktable.unmuted |= DT_DEBUG_LUA; // lua errors are reported on console else if(!strcmp(argv[k + 1], "print")) darktable.unmuted |= DT_DEBUG_PRINT; // print errors are reported on console else if(!strcmp(argv[k + 1], "camsupport")) darktable.unmuted |= DT_DEBUG_CAMERA_SUPPORT; // camera support warnings are reported on console else return usage(argv[0]); k++; argv[k-1] = NULL; argv[k] = NULL; } else if(argv[k][1] == 't' && argc > k + 1) { darktable.num_openmp_threads = CLAMP(atol(argv[k + 1]), 1, 100); printf("[dt_init] using %d threads for openmp parallel sections\n", darktable.num_openmp_threads); k++; argv[k-1] = NULL; argv[k] = NULL; } else if(!strcmp(argv[k], "--conf") && argc > k + 1) { gchar *keyval = g_strdup(argv[++k]), *c = keyval; argv[k-1] = NULL; argv[k] = NULL; gchar *end = keyval + strlen(keyval); while(*c != '=' && c < end) c++; if(*c == '=' && *(c + 1) != '\0') { *c++ = '\0'; dt_conf_string_entry_t *entry = (dt_conf_string_entry_t *)g_malloc(sizeof(dt_conf_string_entry_t)); entry->key = g_strdup(keyval); entry->value = g_strdup(c); config_override = g_slist_append(config_override, entry); } g_free(keyval); } else if(!strcmp(argv[k], "--noiseprofiles") && argc > k + 1) { noiseprofiles_from_command = argv[++k]; argv[k-1] = NULL; argv[k] = NULL; } else if(!strcmp(argv[k], "--luacmd") && argc > k + 1) { #ifdef USE_LUA lua_command = argv[++k]; #else ++k; #endif argv[k-1] = NULL; argv[k] = NULL; } else if(!strcmp(argv[k], "--disable-opencl")) { #ifdef HAVE_OPENCL exclude_opencl = TRUE; #endif argv[k] = NULL; } else if(!strcmp(argv[k], "--")) { // "--" confuses the argument parser of glib/gtk. remove it. argv[k] = NULL; break; } else return usage(argv[0]); // fail on unrecognized options } } // remove the NULLs to not confuse gtk_init() later. for(int i = 1; i < argc; i++) { int k; for(k = i; k < argc; k++) if(argv[k] != NULL) break; if(k > i) { k -= i; for(int j = i + k; j < argc; j++) { argv[j-k] = argv[j]; argv[j] = NULL; } argc -= k; } } if(darktable.unmuted & DT_DEBUG_MEMORY) { fprintf(stderr, "[memory] at startup\n"); dt_print_mem_usage(); } if(init_gui) { // I doubt that connecting to dbus for darktable-cli makes sense darktable.dbus = dt_dbus_init(); // make sure that we have no stale global progress bar visible. thus it's run as early is possible dt_control_progress_init(darktable.control); } #ifdef _OPENMP omp_set_num_threads(darktable.num_openmp_threads); #endif dt_loc_init_datadir(datadir_from_command); dt_loc_init_plugindir(moduledir_from_command); if(dt_loc_init_tmp_dir(tmpdir_from_command)) { fprintf(stderr, "error: invalid temporary directory: %s\n", darktable.tmpdir); return usage(argv[0]); } dt_loc_init_user_config_dir(configdir_from_command); dt_loc_init_user_cache_dir(cachedir_from_command); #ifdef USE_LUA dt_lua_init_early(L); #endif // thread-safe init: dt_exif_init(); char datadir[PATH_MAX] = { 0 }; dt_loc_get_user_config_dir(datadir, sizeof(datadir)); char darktablerc[PATH_MAX] = { 0 }; snprintf(darktablerc, sizeof(darktablerc), "%s/darktablerc", datadir); // initialize the config backend. this needs to be done first... darktable.conf = (dt_conf_t *)calloc(1, sizeof(dt_conf_t)); dt_conf_init(darktable.conf, darktablerc, config_override); g_slist_free_full(config_override, g_free); // set the interface language const gchar *lang = dt_conf_get_string("ui_last/gui_language"); #if defined(_WIN32) // get the default locale if no language preference was specified in the config file if(lang == NULL || lang[0] == '\0') { const wchar_t *wcLocaleName = NULL; wcLocaleName = dtwin_get_locale(); if(wcLocaleName != NULL) { gchar *langLocale; langLocale = g_utf16_to_utf8(wcLocaleName, -1, NULL, NULL, NULL); if(langLocale != NULL) { g_free((gchar *)lang); lang = g_strdup(langLocale); } } } #endif // defined (_WIN32) if(lang != NULL && lang[0] != '\0') { g_setenv("LANGUAGE", lang, 1); if(setlocale(LC_ALL, lang) != NULL) gtk_disable_setlocale(); setlocale(LC_MESSAGES, lang); g_setenv("LANG", lang, 1); } g_free((gchar *)lang); // we need this REALLY early so that error messages can be shown, however after gtk_disable_setlocale if(init_gui) { #ifdef GDK_WINDOWING_WAYLAND // There are currently bad interactions with Wayland (drop-downs // are very narrow, scroll events lost). Until this is fixed, give // priority to the XWayland backend for Wayland users. gdk_set_allowed_backends("x11,*"); #endif gtk_init(&argc, &argv); } // detect cpu features and decide which codepaths to enable dt_codepaths_init(); // get the list of color profiles darktable.color_profiles = dt_colorspaces_init(); // initialize the database darktable.db = dt_database_init(dbfilename_from_command, load_data); if(darktable.db == NULL) { printf("ERROR : cannot open database\n"); return 1; } else if(!dt_database_get_lock_acquired(darktable.db)) { gboolean image_loaded_elsewhere = FALSE; #ifndef MAC_INTEGRATION // send the images to the other instance via dbus fprintf(stderr, "trying to open the images in the running instance\n"); GDBusConnection *connection = NULL; for(int i = 1; i < argc; i++) { // make the filename absolute ... if(argv[i] == NULL || *argv[i] == '\0') continue; gchar *filename = dt_util_normalize_path(argv[i]); if(filename == NULL) continue; if(!connection) connection = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); // ... and send it to the running instance of darktable image_loaded_elsewhere = g_dbus_connection_call_sync(connection, "org.darktable.service", "/darktable", "org.darktable.service.Remote", "Open", g_variant_new("(s)", filename), NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL) != NULL; g_free(filename); } if(connection) g_object_unref(connection); #endif if(!image_loaded_elsewhere) dt_database_show_error(darktable.db); return 1; } // Initialize the signal system darktable.signals = dt_control_signal_init(); // Make sure that the database and xmp files are in sync // We need conf and db to be up and running for that which is the case here. // FIXME: is this also useful in non-gui mode? GList *changed_xmp_files = NULL; if(init_gui && dt_conf_get_bool("run_crawler_on_start")) { changed_xmp_files = dt_control_crawler_run(); } if(init_gui) { dt_control_init(darktable.control); } else { if(dbfilename_from_command && !strcmp(dbfilename_from_command, ":memory:")) dt_gui_presets_init(); // init preset db schema. darktable.control->running = 0; darktable.control->accelerators = NULL; dt_pthread_mutex_init(&darktable.control->run_mutex, NULL); } // initialize collection query darktable.collection = dt_collection_new(NULL); /* initialize selection */ darktable.selection = dt_selection_new(); /* capabilities set to NULL */ darktable.capabilities = NULL; // Initialize the password storage engine darktable.pwstorage = dt_pwstorage_new(); darktable.guides = dt_guides_init(); #ifdef HAVE_GRAPHICSMAGICK /* GraphicsMagick init */ InitializeMagick(darktable.progname); // *SIGH* dt_set_signal_handlers(); #endif darktable.opencl = (dt_opencl_t *)calloc(1, sizeof(dt_opencl_t)); #ifdef HAVE_OPENCL dt_opencl_init(darktable.opencl, exclude_opencl, print_statistics); #endif darktable.points = (dt_points_t *)calloc(1, sizeof(dt_points_t)); dt_points_init(darktable.points, dt_get_num_threads()); darktable.noiseprofile_parser = dt_noiseprofile_init(noiseprofiles_from_command); // must come before mipmap_cache, because that one will need to access // image dimensions stored in here: darktable.image_cache = (dt_image_cache_t *)calloc(1, sizeof(dt_image_cache_t)); dt_image_cache_init(darktable.image_cache); darktable.mipmap_cache = (dt_mipmap_cache_t *)calloc(1, sizeof(dt_mipmap_cache_t)); dt_mipmap_cache_init(darktable.mipmap_cache); // The GUI must be initialized before the views, because the init() // functions of the views depend on darktable.control->accels_* to register // their keyboard accelerators if(init_gui) { darktable.gui = (dt_gui_gtk_t *)calloc(1, sizeof(dt_gui_gtk_t)); if(dt_gui_gtk_init(darktable.gui)) return 1; dt_bauhaus_init(); } else darktable.gui = NULL; darktable.view_manager = (dt_view_manager_t *)calloc(1, sizeof(dt_view_manager_t)); dt_view_manager_init(darktable.view_manager); // check whether we were able to load darkroom view. if we failed, we'll crash everywhere later on. if(!darktable.develop) return 1; darktable.imageio = (dt_imageio_t *)calloc(1, sizeof(dt_imageio_t)); dt_imageio_init(darktable.imageio); // load the darkroom mode plugins once: dt_iop_load_modules_so(); if(init_gui) { #ifdef HAVE_GPHOTO2 // Initialize the camera control. // this is done late so that the gui can react to the signal sent but before switching to lighttable! darktable.camctl = dt_camctl_new(); #endif darktable.lib = (dt_lib_t *)calloc(1, sizeof(dt_lib_t)); dt_lib_init(darktable.lib); dt_gui_gtk_load_config(); // init the gui part of views dt_view_manager_gui_init(darktable.view_manager); // Loading the keybindings char keyfile[PATH_MAX] = { 0 }; // First dump the default keymapping snprintf(keyfile, sizeof(keyfile), "%s/keyboardrc_default", datadir); gtk_accel_map_save(keyfile); // Removing extraneous semi-colons from the default keymap strip_semicolons_from_keymap(keyfile); // Then load any modified keys if available snprintf(keyfile, sizeof(keyfile), "%s/keyboardrc", datadir); if(g_file_test(keyfile, G_FILE_TEST_EXISTS)) gtk_accel_map_load(keyfile); else gtk_accel_map_save(keyfile); // Save the default keymap if none is present // initialize undo struct darktable.undo = dt_undo_init(); } if(darktable.unmuted & DT_DEBUG_MEMORY) { fprintf(stderr, "[memory] after successful startup\n"); dt_print_mem_usage(); } dt_image_local_copy_synch(); /* init lua last, since it's user made stuff it must be in the real environment */ #ifdef USE_LUA dt_lua_init(darktable.lua_state.state, lua_command); #endif if(init_gui) { const char *mode = "lighttable"; // april 1st: you have to earn using dt first! or know that you can switch views with keyboard shortcuts time_t now; time(&now); struct tm lt; localtime_r(&now, <); if(lt.tm_mon == 3 && lt.tm_mday == 1) mode = "knight"; // we have to call dt_ctl_switch_mode_to() here already to not run into a lua deadlock. // having another call later is ok dt_ctl_switch_mode_to(mode); #ifndef MAC_INTEGRATION // load image(s) specified on cmdline. // this has to happen after lua is initialized as image import can run lua code // If only one image is listed, attempt to load it in darkroom int last_id = 0; gboolean only_single_images = TRUE; int loaded_images = 0; for(int i = 1; i < argc; i++) { gboolean single_image = FALSE; if(argv[i] == NULL || *argv[i] == '\0') continue; int new_id = dt_load_from_string(argv[i], FALSE, &single_image); if(new_id > 0) { last_id = new_id; loaded_images++; if(!single_image) only_single_images = FALSE; } } if(loaded_images == 1 && only_single_images) { dt_control_set_mouse_over_id(last_id); dt_ctl_switch_mode_to("darkroom"); } #endif } // last but not least construct the popup that asks the user about images whose xmp files are newer than the // db entry if(init_gui && changed_xmp_files) { dt_control_crawler_show_image_list(changed_xmp_files); } dt_print(DT_DEBUG_CONTROL, "[init] startup took %f seconds\n", dt_get_wtime() - start_wtime); return 0; }
dt_database_t *dt_database_init(char *alternative) { /* migrate default database location to new default */ _database_migrate_to_xdg_structure(); /* delete old mipmaps files */ _database_delete_mipmaps_files(); /* lets construct the db filename */ gchar * dbname = NULL; gchar dbfilename[1024] = {0}; gchar datadir[1024] = {0}; dt_loc_get_user_config_dir(datadir, 1024); if ( alternative == NULL ) { dbname = dt_conf_get_string ("database"); if(!dbname) snprintf(dbfilename, 1024, "%s/library.db", datadir); else if(dbname[0] != '/') snprintf(dbfilename, 1024, "%s/%s", datadir, dbname); else snprintf(dbfilename, 1024, "%s", dbname); } else { snprintf(dbfilename, 1024, "%s", alternative); dbname = g_file_get_basename (g_file_new_for_path(alternative)); } /* create database */ dt_database_t *db = (dt_database_t *)g_malloc(sizeof(dt_database_t)); memset(db,0,sizeof(dt_database_t)); db->dbfilename = g_strdup(dbfilename); db->is_new_database = FALSE; /* test if databasefile is available */ if(!g_file_test(dbfilename, G_FILE_TEST_IS_REGULAR)) db->is_new_database = TRUE; /* opening / creating database */ if(sqlite3_open(db->dbfilename, &db->handle)) { fprintf(stderr, "[init] could not find database "); if(dbname) fprintf(stderr, "`%s'!\n", dbname); else fprintf(stderr, "\n"); fprintf(stderr, "[init] maybe your %s/darktablerc is corrupt?\n",datadir); dt_loc_get_datadir(dbfilename, 512); fprintf(stderr, "[init] try `cp %s/darktablerc %s/darktablerc'\n", dbfilename,datadir); g_free(dbname); g_free(db); return NULL; } /* attach a memory database to db connection for use with temporary tables used during instance life time, which is discarded on exit. */ sqlite3_exec(db->handle, "attach database ':memory:' as memory",NULL,NULL,NULL); sqlite3_exec(db->handle, "PRAGMA synchronous = OFF", NULL, NULL, NULL); sqlite3_exec(db->handle, "PRAGMA journal_mode = MEMORY", NULL, NULL, NULL); sqlite3_exec(db->handle, "PRAGMA page_size = 32768", NULL, NULL, NULL); g_free(dbname); return db; }
void gui_init(struct dt_iop_module_t *self) { self->gui_data = malloc(sizeof(dt_iop_colorout_gui_data_t)); memset(self->gui_data,0,sizeof(dt_iop_colorout_gui_data_t)); dt_iop_colorout_gui_data_t *g = (dt_iop_colorout_gui_data_t *)self->gui_data; g->profiles = NULL; dt_iop_color_profile_t *prof = (dt_iop_color_profile_t *)g_malloc0(sizeof(dt_iop_color_profile_t)); g_strlcpy(prof->filename, "sRGB", sizeof(prof->filename)); g_strlcpy(prof->name, "sRGB", sizeof(prof->name)); int pos; int display_pos; prof->pos = 0; prof->display_pos = 0; g->profiles = g_list_append(g->profiles, prof); prof = (dt_iop_color_profile_t *)g_malloc0(sizeof(dt_iop_color_profile_t)); g_strlcpy(prof->filename, "adobergb", sizeof(prof->filename)); g_strlcpy(prof->name, "adobergb", sizeof(prof->name)); prof->pos = 1; prof->display_pos = 1; g->profiles = g_list_append(g->profiles, prof); prof = (dt_iop_color_profile_t *)g_malloc0(sizeof(dt_iop_color_profile_t)); g_strlcpy(prof->filename, "X profile", sizeof(prof->filename)); g_strlcpy(prof->name, "X profile", sizeof(prof->name)); prof->pos = -1; prof->display_pos = 2; g->profiles = g_list_append(g->profiles, prof); prof = (dt_iop_color_profile_t *)g_malloc0(sizeof(dt_iop_color_profile_t)); g_strlcpy(prof->filename, "linear_rgb", sizeof(prof->filename)); g_strlcpy(prof->name, "linear_rgb", sizeof(prof->name)); pos = prof->pos = 2; display_pos = prof->display_pos = 3; g->profiles = g_list_append(g->profiles, prof); // read {conf,data}dir/color/out/*.icc char datadir[DT_MAX_PATH_LEN]; char confdir[DT_MAX_PATH_LEN]; char dirname[DT_MAX_PATH_LEN]; char filename[DT_MAX_PATH_LEN]; dt_loc_get_user_config_dir(confdir, DT_MAX_PATH_LEN); dt_loc_get_datadir(datadir, DT_MAX_PATH_LEN); snprintf(dirname, DT_MAX_PATH_LEN, "%s/color/out", confdir); if(!g_file_test(dirname, G_FILE_TEST_IS_DIR)) snprintf(dirname, DT_MAX_PATH_LEN, "%s/color/out", datadir); cmsHPROFILE tmpprof; const gchar *d_name; GDir *dir = g_dir_open(dirname, 0, NULL); if(dir) { while((d_name = g_dir_read_name(dir))) { snprintf(filename, DT_MAX_PATH_LEN, "%s/%s", dirname, d_name); tmpprof = cmsOpenProfileFromFile(filename, "r"); if(tmpprof) { char *lang = getenv("LANG"); if (!lang) lang = "en_US"; dt_iop_color_profile_t *prof = (dt_iop_color_profile_t *)g_malloc0(sizeof(dt_iop_color_profile_t)); char name[1024]; cmsGetProfileInfoASCII(tmpprof, cmsInfoDescription, lang, lang+3, name, 1024); g_strlcpy(prof->name, name, sizeof(prof->name)); g_strlcpy(prof->filename, d_name, sizeof(prof->filename)); prof->pos = ++pos; prof->display_pos = ++display_pos; cmsCloseProfile(tmpprof); g->profiles = g_list_append(g->profiles, prof); } } g_dir_close(dir); } self->widget = gtk_vbox_new(TRUE, DT_BAUHAUS_SPACE); // TODO: g->cbox1 = dt_bauhaus_combobox_new(self); gtk_box_pack_start(GTK_BOX(self->widget), g->cbox1, TRUE, TRUE, 0); dt_bauhaus_widget_set_label(g->cbox1, _("output intent")); dt_bauhaus_combobox_add(g->cbox1, _("perceptual")); dt_bauhaus_combobox_add(g->cbox1, _("relative colorimetric")); dt_bauhaus_combobox_add(g->cbox1, C_("rendering intent", "saturation")); dt_bauhaus_combobox_add(g->cbox1, _("absolute colorimetric")); g->cbox4 = dt_bauhaus_combobox_new(self); dt_bauhaus_widget_set_label(g->cbox4, _("display intent")); gtk_box_pack_start(GTK_BOX(self->widget), g->cbox4, TRUE, TRUE, 0); dt_bauhaus_combobox_add(g->cbox4, _("perceptual")); dt_bauhaus_combobox_add(g->cbox4, _("relative colorimetric")); dt_bauhaus_combobox_add(g->cbox4, C_("rendering intent", "saturation")); dt_bauhaus_combobox_add(g->cbox4, _("absolute colorimetric")); g->cbox2 = dt_bauhaus_combobox_new(self); g->cbox3 = dt_bauhaus_combobox_new(self); g->cbox5 = dt_bauhaus_combobox_new(self); dt_bauhaus_widget_set_label(g->cbox2, _("output profile")); dt_bauhaus_widget_set_label(g->cbox5, _("softproof profile")); dt_bauhaus_widget_set_label(g->cbox3, _("display profile")); gtk_box_pack_start(GTK_BOX(self->widget), g->cbox2, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(self->widget), g->cbox5, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(self->widget), g->cbox3, TRUE, TRUE, 0); GList *l = g->profiles; while(l) { dt_iop_color_profile_t *prof = (dt_iop_color_profile_t *)l->data; if(!strcmp(prof->name, "X profile")) { // the system display profile is only suitable for display purposes dt_bauhaus_combobox_add(g->cbox3, _("system display profile")); } else if(!strcmp(prof->name, "linear_rgb")) { dt_bauhaus_combobox_add(g->cbox2, _("linear RGB")); dt_bauhaus_combobox_add(g->cbox3, _("linear RGB")); dt_bauhaus_combobox_add(g->cbox5, _("linear RGB")); } else if(!strcmp(prof->name, "sRGB")) { dt_bauhaus_combobox_add(g->cbox2, _("sRGB (web-safe)")); dt_bauhaus_combobox_add(g->cbox3, _("sRGB (web-safe)")); dt_bauhaus_combobox_add(g->cbox5, _("sRGB (web-safe)")); } else if(!strcmp(prof->name, "adobergb")) { dt_bauhaus_combobox_add(g->cbox2, _("Adobe RGB")); dt_bauhaus_combobox_add(g->cbox3, _("Adobe RGB")); dt_bauhaus_combobox_add(g->cbox5, _("Adobe RGB")); } else { dt_bauhaus_combobox_add(g->cbox2, prof->name); dt_bauhaus_combobox_add(g->cbox3, prof->name); dt_bauhaus_combobox_add(g->cbox5, prof->name); } l = g_list_next(l); } char tooltip[1024]; g_object_set(G_OBJECT(g->cbox1), "tooltip-text", _("rendering intent"), (char *)NULL); snprintf(tooltip, 1024, _("icc profiles in %s/color/out or %s/color/out"), confdir, datadir); g_object_set(G_OBJECT(g->cbox2), "tooltip-text", tooltip, (char *)NULL); snprintf(tooltip, 1024, _("display icc profiles in %s/color/out or %s/color/out"), confdir, datadir); g_object_set(G_OBJECT(g->cbox3), "tooltip-text", tooltip, (char *)NULL); snprintf(tooltip, 1024, _("softproof icc profiles in %s/color/out or %s/color/out"), confdir, datadir); g_object_set(G_OBJECT(g->cbox5), "tooltip-text", tooltip, (char *)NULL); g_signal_connect (G_OBJECT (g->cbox1), "value-changed", G_CALLBACK (intent_changed), (gpointer)self); g_signal_connect (G_OBJECT (g->cbox4), "value-changed", G_CALLBACK (display_intent_changed), (gpointer)self); g_signal_connect (G_OBJECT (g->cbox2), "value-changed", G_CALLBACK (output_profile_changed), (gpointer)self); g_signal_connect (G_OBJECT (g->cbox3), "value-changed", G_CALLBACK (display_profile_changed), (gpointer)self); g_signal_connect (G_OBJECT (g->cbox5), "value-changed", G_CALLBACK (softproof_profile_changed), (gpointer)self); // reload the profiles when the display profile changed! dt_control_signal_connect(darktable.signals, DT_SIGNAL_CONTROL_PROFILE_CHANGED, G_CALLBACK(_signal_profile_changed), self); }
gboolean dt_styles_create_from_image(const char *name, const char *description, int32_t imgid, GList *filter) { int id = 0; sqlite3_stmt *stmt; /* first create the style header */ if(!dt_styles_create_style_header(name, description)) return FALSE; if((id = dt_styles_get_id_by_name(name)) != 0) { /* create the style_items from source image history stack */ if(filter) { GList *list = filter; char tmp[64]; char include[2048] = { 0 }; g_strlcat(include, "num in (", sizeof(include)); do { if(list != g_list_first(list)) g_strlcat(include, ",", sizeof(include)); snprintf(tmp, sizeof(tmp), "%d", GPOINTER_TO_INT(list->data)); g_strlcat(include, tmp, sizeof(include)); } while((list = g_list_next(list))); g_strlcat(include, ")", sizeof(include)); char query[4096] = { 0 }; snprintf(query, sizeof(query), "insert into style_items " "(styleid,num,module,operation,op_params,enabled,blendop_params,blendop_" "version,multi_priority,multi_name) select ?1, " "num,module,operation,op_params,enabled,blendop_params,blendop_version," "multi_priority,multi_name from history where imgid=?2 and %s", include); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), query, -1, &stmt, NULL); } else DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "insert into style_items " "(styleid,num,module,operation,op_params,enabled,blendop_params,blendop_" "version,multi_priority,multi_name) select ?1, " "num,module,operation,op_params,enabled,blendop_params,blendop_version," "multi_priority,multi_name from history where imgid=?2", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid); sqlite3_step(stmt); sqlite3_finalize(stmt); _dt_style_cleanup_multi_instance(id); /* backup style to disk */ char stylesdir[PATH_MAX] = { 0 }; dt_loc_get_user_config_dir(stylesdir, sizeof(stylesdir)); g_strlcat(stylesdir, "/styles", sizeof(stylesdir)); g_mkdir_with_parents(stylesdir, 00755); dt_styles_save_to_file(name, stylesdir, FALSE); char tmp_accel[1024]; gchar *tmp_name = g_strdup(name); // freed by _destroy_style_shortcut_callback snprintf(tmp_accel, sizeof(tmp_accel), C_("accel", "styles/apply %s"), name); dt_accel_register_global(tmp_accel, 0, 0); GClosure *closure; closure = g_cclosure_new(G_CALLBACK(_apply_style_shortcut_callback), tmp_name, _destroy_style_shortcut_callback); dt_accel_connect_global(tmp_accel, closure); dt_control_signal_raise(darktable.signals, DT_SIGNAL_STYLE_CHANGED); return TRUE; } return FALSE; }
int dt_lua_init_configuration(lua_State*L) { char tmp_path[PATH_MAX]; dt_lua_push_darktable_lib(L); dt_lua_goto_subtable(L,"configuration"); // build the table containing the configuration info lua_pushstring(L,"tmp_dir"); dt_loc_get_tmp_dir(tmp_path, PATH_MAX); lua_pushstring(L,tmp_path); lua_settable(L,-3); lua_pushstring(L,"config_dir"); dt_loc_get_user_config_dir(tmp_path, PATH_MAX); lua_pushstring(L,tmp_path); lua_settable(L,-3); lua_pushstring(L,"cache_dir"); dt_loc_get_user_cache_dir(tmp_path, PATH_MAX); lua_pushstring(L,tmp_path); lua_settable(L,-3); lua_pushstring(L,"version"); lua_pushstring(L,PACKAGE_VERSION); lua_settable(L,-3); lua_pushstring(L,"verbose"); lua_pushboolean(L,darktable.unmuted & DT_DEBUG_LUA); lua_settable(L,-3); lua_pushstring(L,"has_gui"); lua_pushboolean(L,darktable.gui != NULL); lua_settable(L,-3); lua_pushstring(L,"api_version_major"); lua_pushnumber(L,API_VERSION_MAJOR); lua_settable(L,-3); lua_pushstring(L,"api_version_minor"); lua_pushnumber(L,API_VERSION_MINOR); lua_settable(L,-3); lua_pushstring(L,"api_version_patch"); lua_pushnumber(L,API_VERSION_PATCH); lua_settable(L,-3); lua_pushstring(L,"api_version_suffix"); lua_pushstring(L,API_VERSION_SUFFIX); lua_settable(L,-3); lua_pushstring(L,"api_version_string"); if (strcmp(API_VERSION_SUFFIX, "") == 0) { lua_pushfstring(L,"%d.%d.%d",API_VERSION_MAJOR,API_VERSION_MINOR,API_VERSION_PATCH); } else { lua_pushfstring(L,"%d.%d.%d-%s",API_VERSION_MAJOR,API_VERSION_MINOR,API_VERSION_PATCH,API_VERSION_SUFFIX); } lua_settable(L,-3); lua_pop(L,1); //remove the configuration table from the stack return 0; }
void gui_init (dt_lib_module_t *self) { dt_lib_export_t *d = (dt_lib_export_t *)malloc(sizeof(dt_lib_export_t)); self->data = (void *)d; self->widget = gtk_table_new(8, 2, FALSE); gtk_table_set_row_spacings(GTK_TABLE(self->widget), 5); GtkWidget *label; label = dtgtk_label_new(_("target storage"), DARKTABLE_LABEL_TAB | DARKTABLE_LABEL_ALIGN_RIGHT); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(self->widget), label, 0, 2, 0, 1, GTK_FILL|GTK_EXPAND, 0, 0, 0); d->storage = GTK_COMBO_BOX(gtk_combo_box_new_text()); GList *it = darktable.imageio->plugins_storage; while(it) { dt_imageio_module_storage_t *module = (dt_imageio_module_storage_t *)it->data; gtk_combo_box_append_text(d->storage, module->name(module)); it = g_list_next(it); } dt_control_signal_connect(darktable.signals,DT_SIGNAL_IMAGEIO_STORAGE_CHANGE,G_CALLBACK(on_storage_list_changed),self); gtk_table_attach(GTK_TABLE(self->widget), GTK_WIDGET(d->storage), 0, 2, 1, 2, GTK_EXPAND|GTK_FILL, 0, 0, 0); g_signal_connect (G_OBJECT (d->storage), "changed", G_CALLBACK (storage_changed), (gpointer)d); d->storage_box = GTK_CONTAINER(gtk_alignment_new(1.0, 1.0, 1.0, 1.0)); gtk_alignment_set_padding(GTK_ALIGNMENT(d->storage_box), 0, 0, 0, 0); gtk_table_attach(GTK_TABLE(self->widget), GTK_WIDGET(d->storage_box), 0, 2, 2, 3, GTK_EXPAND|GTK_FILL, 0, 0, 0); label = dtgtk_label_new(_("file format"), DARKTABLE_LABEL_TAB | DARKTABLE_LABEL_ALIGN_RIGHT); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_set_row_spacing(GTK_TABLE(self->widget), 2, 20); gtk_table_attach(GTK_TABLE(self->widget), label, 0, 2, 3, 4, GTK_EXPAND|GTK_FILL, 0, 0, 0); d->format = GTK_COMBO_BOX(gtk_combo_box_new_text()); gtk_table_attach(GTK_TABLE(self->widget), GTK_WIDGET(d->format), 0, 2, 4, 5, GTK_EXPAND|GTK_FILL, 0, 0, 0); g_signal_connect (G_OBJECT (d->format), "changed", G_CALLBACK (format_changed), (gpointer)d); d->format_box = GTK_CONTAINER(gtk_alignment_new(1.0, 1.0, 1.0, 1.0)); gtk_alignment_set_padding(GTK_ALIGNMENT(d->format_box), 0, 0, 0, 0); gtk_table_attach(GTK_TABLE(self->widget), GTK_WIDGET(d->format_box), 0, 2, 5, 6, GTK_EXPAND|GTK_FILL, 0, 0, 0); label = dtgtk_label_new(_("global options"), DARKTABLE_LABEL_TAB | DARKTABLE_LABEL_ALIGN_RIGHT); gtk_table_set_row_spacing(GTK_TABLE(self->widget), 5, 20); gtk_table_attach(GTK_TABLE(self->widget), label, 0, 2, 6, 7, GTK_EXPAND|GTK_FILL, 0, 0, 0); d->width = GTK_SPIN_BUTTON(gtk_spin_button_new_with_range(0, 10000, 1)); g_object_set(G_OBJECT(d->width), "tooltip-text", _("maximum output width\nset to 0 for no scaling"), (char *)NULL); d->height = GTK_SPIN_BUTTON(gtk_spin_button_new_with_range(0, 10000, 1)); g_object_set(G_OBJECT(d->height), "tooltip-text", _("maximum output height\nset to 0 for no scaling"), (char *)NULL); dt_gui_key_accel_block_on_focus_connect (GTK_WIDGET (d->width)); dt_gui_key_accel_block_on_focus_connect (GTK_WIDGET (d->height)); /* gtk_widget_add_events(GTK_WIDGET(d->width), GDK_FOCUS_CHANGE_MASK); g_signal_connect (G_OBJECT (d->width), "focus-in-event", G_CALLBACK(focus_in), NULL); g_signal_connect (G_OBJECT (d->width), "focus-out-event", G_CALLBACK(focus_out), NULL); gtk_widget_add_events(GTK_WIDGET(d->height), GDK_FOCUS_CHANGE_MASK); g_signal_connect (G_OBJECT (d->height), "focus-in-event", G_CALLBACK(focus_in), NULL); g_signal_connect (G_OBJECT (d->height), "focus-out-event", G_CALLBACK(focus_out), NULL); */ label = gtk_label_new(_("max size")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(self->widget), label, 0, 1, 7, 8, GTK_EXPAND|GTK_FILL, 0, 0, 0); GtkBox *hbox = GTK_BOX(gtk_hbox_new(FALSE, 5)); gtk_box_pack_start(hbox, GTK_WIDGET(d->width), TRUE, TRUE, 0); gtk_box_pack_start(hbox, gtk_label_new(_("x")), FALSE, FALSE, 0); gtk_box_pack_start(hbox, GTK_WIDGET(d->height), TRUE, TRUE, 0); gtk_table_attach(GTK_TABLE(self->widget), GTK_WIDGET(hbox), 1, 2, 7, 8, GTK_EXPAND|GTK_FILL, 0, 0, 0); label = gtk_label_new(_("intent")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(self->widget), label, 0, 1, 8, 9, GTK_EXPAND|GTK_FILL, 0, 0, 0); d->intent = GTK_COMBO_BOX(gtk_combo_box_new_text()); gtk_combo_box_append_text(d->intent, _("image settings")); gtk_combo_box_append_text(d->intent, _("perceptual")); gtk_combo_box_append_text(d->intent, _("relative colorimetric")); gtk_combo_box_append_text(d->intent, C_("rendering intent", "saturation")); gtk_combo_box_append_text(d->intent, _("absolute colorimetric")); gtk_table_attach(GTK_TABLE(self->widget), GTK_WIDGET(d->intent), 1, 2, 8, 9, GTK_EXPAND|GTK_FILL, 0, 0, 0); // Add profile combo d->profiles = NULL; dt_lib_export_profile_t *prof = (dt_lib_export_profile_t *)g_malloc0(sizeof(dt_lib_export_profile_t)); g_strlcpy(prof->filename, "sRGB", sizeof(prof->filename)); g_strlcpy(prof->name, _("sRGB (web-safe)"), sizeof(prof->name)); int pos; prof->pos = 1; d->profiles = g_list_append(d->profiles, prof); prof = (dt_lib_export_profile_t *)g_malloc0(sizeof(dt_lib_export_profile_t)); g_strlcpy(prof->filename, "adobergb", sizeof(prof->filename)); g_strlcpy(prof->name, _("Adobe RGB"), sizeof(prof->name)); prof->pos = 2; d->profiles = g_list_append(d->profiles, prof); prof = (dt_lib_export_profile_t *)g_malloc0(sizeof(dt_lib_export_profile_t)); g_strlcpy(prof->filename, "X profile", sizeof(prof->filename)); g_strlcpy(prof->name, "X profile", sizeof(prof->name)); prof->pos = 3; d->profiles = g_list_append(d->profiles, prof); prof = (dt_lib_export_profile_t *)g_malloc0(sizeof(dt_lib_export_profile_t)); g_strlcpy(prof->filename, "linear_rgb", sizeof(prof->filename)); g_strlcpy(prof->name, _("linear RGB"), sizeof(prof->name)); pos = prof->pos = 4; d->profiles = g_list_append(d->profiles, prof); // read datadir/color/out/*.icc char datadir[DT_MAX_PATH_LEN]; char confdir[DT_MAX_PATH_LEN]; char dirname[DT_MAX_PATH_LEN]; char filename[DT_MAX_PATH_LEN]; dt_loc_get_user_config_dir(confdir, DT_MAX_PATH_LEN); dt_loc_get_datadir(datadir, DT_MAX_PATH_LEN); cmsHPROFILE tmpprof; const gchar *d_name; snprintf(dirname, DT_MAX_PATH_LEN, "%s/color/out", confdir); if(!g_file_test(dirname, G_FILE_TEST_IS_DIR)) snprintf(dirname, DT_MAX_PATH_LEN, "%s/color/out", datadir); GDir *dir = g_dir_open(dirname, 0, NULL); if(dir) { while((d_name = g_dir_read_name(dir))) { snprintf(filename, DT_MAX_PATH_LEN, "%s/%s", dirname, d_name); tmpprof = cmsOpenProfileFromFile(filename, "r"); if(tmpprof) { char *lang = getenv("LANG"); if (!lang) lang = "en_US"; dt_lib_export_profile_t *prof = (dt_lib_export_profile_t *)g_malloc0(sizeof(dt_lib_export_profile_t)); char name[1024]; cmsGetProfileInfoASCII(tmpprof, cmsInfoDescription, lang, lang+3, name, 1024); g_strlcpy(prof->name, name, sizeof(prof->name)); g_strlcpy(prof->filename, d_name, sizeof(prof->filename)); prof->pos = ++pos; cmsCloseProfile(tmpprof); d->profiles = g_list_append(d->profiles, prof); } } g_dir_close(dir); } GList *l = d->profiles; label = gtk_label_new(_("profile")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(self->widget), label, 0, 1, 9, 10, GTK_EXPAND|GTK_FILL, 0, 0, 0); d->profile = GTK_COMBO_BOX(gtk_combo_box_new_text()); dt_ellipsize_combo(d->profile); gtk_table_attach(GTK_TABLE(self->widget), GTK_WIDGET(d->profile), 1, 2, 9, 10, GTK_SHRINK|GTK_EXPAND|GTK_FILL, 0, 0, 0); // gtk_table_attach(GTK_TABLE(self->widget), GTK_WIDGET(d->profile), 1, 2, 9, 10, GTK_EXPAND|GTK_FILL, 0, 0, 0); gtk_combo_box_append_text(d->profile, _("image settings")); while(l) { dt_lib_export_profile_t *prof = (dt_lib_export_profile_t *)l->data; if(!strcmp(prof->name, "X profile")) gtk_combo_box_append_text(d->profile, _("system display profile")); else gtk_combo_box_append_text(d->profile, prof->name); l = g_list_next(l); } gtk_combo_box_set_active(d->profile, 0); char tooltip[1024]; snprintf(tooltip, 1024, _("output icc profiles in %s/color/out or %s/color/out"), confdir, datadir); g_object_set(G_OBJECT(d->profile), "tooltip-text", tooltip, (char *)NULL); // Add style combo label = gtk_label_new(_("style")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(self->widget), label, 0, 1, 10, 11, GTK_EXPAND|GTK_FILL, 0, 0, 0); d->style = GTK_COMBO_BOX(gtk_combo_box_new_text()); dt_ellipsize_combo(d->style); gtk_combo_box_append_text(d->style, _("none")); GList *styles = dt_styles_get_list(""); while (styles) { dt_style_t *style=(dt_style_t *)styles->data; gtk_combo_box_append_text(d->style, style->name); styles=g_list_next(styles); } gtk_table_attach(GTK_TABLE(self->widget), GTK_WIDGET(d->style), 1, 2, 10, 11, GTK_EXPAND|GTK_FILL, 0, 0, 0); g_object_set(G_OBJECT(d->style), "tooltip-text", _("temporary style to append while exporting"), (char *)NULL); // Set callback signals g_signal_connect (G_OBJECT (d->intent), "changed", G_CALLBACK (intent_changed), (gpointer)d); g_signal_connect (G_OBJECT (d->profile), "changed", G_CALLBACK (profile_changed), (gpointer)d); g_signal_connect (G_OBJECT (d->style), "changed", G_CALLBACK (style_changed), (gpointer)d); // Export button GtkButton *button = GTK_BUTTON(gtk_button_new_with_label(_("export"))); d->export_button = button; g_object_set(G_OBJECT(button), "tooltip-text", _("export with current settings (ctrl-e)"), (char *)NULL); gtk_table_attach(GTK_TABLE(self->widget), GTK_WIDGET(button), 1, 2, 11, 12, GTK_EXPAND|GTK_FILL, 0, 0, 0); g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (export_button_clicked), (gpointer)self); g_signal_connect (G_OBJECT (d->width), "value-changed", G_CALLBACK (width_changed), (gpointer)0); g_signal_connect (G_OBJECT (d->height), "value-changed", G_CALLBACK (height_changed), (gpointer)0); self->gui_reset(self); }
int dt_init(int argc, char *argv[], const int init_gui) { // make everything go a lot faster. _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); #ifndef __APPLE__ _dt_sigsegv_old_handler = signal(SIGSEGV,&_dt_sigsegv_handler); #endif #ifndef __SSE2__ fprintf(stderr, "[dt_init] unfortunately we depend on SSE2 instructions at this time.\n"); fprintf(stderr, "[dt_init] please contribute a backport patch (or buy a newer processor).\n"); return 1; #endif #ifdef M_MMAP_THRESHOLD mallopt(M_MMAP_THRESHOLD,128*1024) ; /* use mmap() for large allocations */ #endif bindtextdomain (GETTEXT_PACKAGE, DARKTABLE_LOCALEDIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); // init all pointers to 0: memset(&darktable, 0, sizeof(darktable_t)); darktable.progname = argv[0]; // database gchar *dbfilename_from_command = NULL; char *datadir_from_command = NULL; char *moduledir_from_command = NULL; char *tmpdir_from_command = NULL; char *configdir_from_command = NULL; char *cachedir_from_command = NULL; darktable.num_openmp_threads = 1; #ifdef _OPENMP darktable.num_openmp_threads = omp_get_num_procs(); #endif darktable.unmuted = 0; GSList *images_to_load = NULL; for(int k=1; k<argc; k++) { if(argv[k][0] == '-') { if(!strcmp(argv[k], "--help")) { return usage(argv[0]); } if(!strcmp(argv[k], "-h")) { return usage(argv[0]); } else if(!strcmp(argv[k], "--version")) { printf("this is "PACKAGE_STRING"\ncopyright (c) 2009-2013 johannes hanika\n"PACKAGE_BUGREPORT"\n"); return 1; } else if(!strcmp(argv[k], "--library")) { dbfilename_from_command = argv[++k]; } else if(!strcmp(argv[k], "--datadir")) { datadir_from_command = argv[++k]; } else if(!strcmp(argv[k], "--moduledir")) { moduledir_from_command = argv[++k]; } else if(!strcmp(argv[k], "--tmpdir")) { tmpdir_from_command = argv[++k]; } else if(!strcmp(argv[k], "--configdir")) { configdir_from_command = argv[++k]; } else if(!strcmp(argv[k], "--cachedir")) { cachedir_from_command = argv[++k]; } else if(!strcmp(argv[k], "--localedir")) { bindtextdomain (GETTEXT_PACKAGE, argv[++k]); } else if(argv[k][1] == 'd' && argc > k+1) { if(!strcmp(argv[k+1], "all")) darktable.unmuted = 0xffffffff; // enable all debug information else if(!strcmp(argv[k+1], "cache")) darktable.unmuted |= DT_DEBUG_CACHE; // enable debugging for lib/film/cache module else if(!strcmp(argv[k+1], "control")) darktable.unmuted |= DT_DEBUG_CONTROL; // enable debugging for scheduler module else if(!strcmp(argv[k+1], "dev")) darktable.unmuted |= DT_DEBUG_DEV; // develop module else if(!strcmp(argv[k+1], "fswatch")) darktable.unmuted |= DT_DEBUG_FSWATCH; // fswatch module else if(!strcmp(argv[k+1], "camctl")) darktable.unmuted |= DT_DEBUG_CAMCTL; // camera control module else if(!strcmp(argv[k+1], "perf")) darktable.unmuted |= DT_DEBUG_PERF; // performance measurements else if(!strcmp(argv[k+1], "pwstorage")) darktable.unmuted |= DT_DEBUG_PWSTORAGE; // pwstorage module else if(!strcmp(argv[k+1], "opencl")) darktable.unmuted |= DT_DEBUG_OPENCL; // gpu accel via opencl else if(!strcmp(argv[k+1], "sql")) darktable.unmuted |= DT_DEBUG_SQL; // SQLite3 queries else if(!strcmp(argv[k+1], "memory")) darktable.unmuted |= DT_DEBUG_MEMORY; // some stats on mem usage now and then. else if(!strcmp(argv[k+1], "lighttable")) darktable.unmuted |= DT_DEBUG_LIGHTTABLE; // lighttable related stuff. else if(!strcmp(argv[k+1], "nan")) darktable.unmuted |= DT_DEBUG_NAN; // check for NANs when processing the pipe. else return usage(argv[0]); k ++; } else if(argv[k][1] == 't' && argc > k+1) { darktable.num_openmp_threads = CLAMP(atol(argv[k+1]), 1, 100); printf("[dt_init] using %d threads for openmp parallel sections\n", darktable.num_openmp_threads); k ++; } } #ifndef MAC_INTEGRATION else { images_to_load = g_slist_append(images_to_load, argv[k]); } #endif } if(darktable.unmuted & DT_DEBUG_MEMORY) { fprintf(stderr, "[memory] at startup\n"); dt_print_mem_usage(); } #ifdef _OPENMP omp_set_num_threads(darktable.num_openmp_threads); #endif dt_loc_init_datadir(datadir_from_command); dt_loc_init_plugindir(moduledir_from_command); if(dt_loc_init_tmp_dir(tmpdir_from_command)) { printf(_("ERROR : invalid temporary directory : %s\n"),darktable.tmpdir); return usage(argv[0]); } dt_loc_init_user_config_dir(configdir_from_command); dt_loc_init_user_cache_dir(cachedir_from_command); #if !GLIB_CHECK_VERSION(2, 35, 0) g_type_init(); #endif // does not work, as gtk is not inited yet. // even if it were, it's a super bad idea to invoke gtk stuff from // a signal handler. /* check cput caps */ // dt_check_cpu(argc,argv); #ifdef HAVE_GEGL char geglpath[DT_MAX_PATH_LEN]; char datadir[DT_MAX_PATH_LEN]; dt_loc_get_datadir(datadir, DT_MAX_PATH_LEN); snprintf(geglpath, DT_MAX_PATH_LEN, "%s/gegl:/usr/lib/gegl-0.0", datadir); (void)setenv("GEGL_PATH", geglpath, 1); gegl_init(&argc, &argv); #endif // thread-safe init: dt_exif_init(); char datadir[DT_MAX_PATH_LEN]; dt_loc_get_user_config_dir (datadir,DT_MAX_PATH_LEN); char filename[DT_MAX_PATH_LEN]; snprintf(filename, DT_MAX_PATH_LEN, "%s/darktablerc", datadir); // intialize the config backend. this needs to be done first... darktable.conf = (dt_conf_t *)malloc(sizeof(dt_conf_t)); memset(darktable.conf, 0, sizeof(dt_conf_t)); dt_conf_init(darktable.conf, filename); // set the interface language const gchar* lang = dt_conf_get_string("ui_last/gui_language"); if(lang != NULL && lang[0] != '\0') { if(setlocale(LC_ALL, lang) != NULL) gtk_disable_setlocale(); } // initialize the database darktable.db = dt_database_init(dbfilename_from_command); if(darktable.db == NULL) { printf("ERROR : cannot open database\n"); return 1; } else if(dt_database_get_already_locked(darktable.db)) { // send the images to the other instance via dbus if(images_to_load) { GSList *p = images_to_load; // get a connection! GDBusConnection *connection = g_bus_get_sync(G_BUS_TYPE_SESSION,NULL, NULL); while (p != NULL) { // make the filename absolute ... gchar *filename = dt_make_path_absolute((gchar*)p->data); if(filename == NULL) continue; // ... and send it to the running instance of darktable g_dbus_connection_call_sync(connection, "org.darktable.service", "/darktable", "org.darktable.service.Remote", "Open", g_variant_new ("(s)", filename), NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL); p = g_slist_next(p); g_free(filename); } g_slist_free(images_to_load); g_object_unref(connection); } return 1; } // Initialize the signal system darktable.signals = dt_control_signal_init(); // Initialize the filesystem watcher darktable.fswatch=dt_fswatch_new(); #ifdef HAVE_GPHOTO2 // Initialize the camera control darktable.camctl=dt_camctl_new(); #endif // get max lighttable thumbnail size: darktable.thumbnail_width = CLAMPS(dt_conf_get_int("plugins/lighttable/thumbnail_width"), 200, 3000); darktable.thumbnail_height = CLAMPS(dt_conf_get_int("plugins/lighttable/thumbnail_height"), 200, 3000); // and make sure it can be mip-mapped all the way from mip4 to mip0 darktable.thumbnail_width /= 16; darktable.thumbnail_width *= 16; darktable.thumbnail_height /= 16; darktable.thumbnail_height *= 16; // Initialize the password storage engine darktable.pwstorage=dt_pwstorage_new(); // FIXME: move there into dt_database_t dt_pthread_mutex_init(&(darktable.db_insert), NULL); dt_pthread_mutex_init(&(darktable.plugin_threadsafe), NULL); dt_pthread_mutex_init(&(darktable.capabilities_threadsafe), NULL); darktable.control = (dt_control_t *)malloc(sizeof(dt_control_t)); memset(darktable.control, 0, sizeof(dt_control_t)); if(init_gui) { dt_control_init(darktable.control); } else { // this is in memory, so schema can't exist yet. if(dbfilename_from_command && !strcmp(dbfilename_from_command, ":memory:")) { dt_control_create_database_schema(); dt_gui_presets_init(); // also init preset db schema. } darktable.control->running = 0; darktable.control->accelerators = NULL; dt_pthread_mutex_init(&darktable.control->run_mutex, NULL); } // initialize collection query darktable.collection_listeners = NULL; darktable.collection = dt_collection_new(NULL); /* initialize sellection */ darktable.selection = dt_selection_new(); /* capabilities set to NULL */ darktable.capabilities = NULL; #ifdef HAVE_GRAPHICSMAGICK /* GraphicsMagick init */ InitializeMagick(darktable.progname); #endif darktable.opencl = (dt_opencl_t *)malloc(sizeof(dt_opencl_t)); memset(darktable.opencl, 0, sizeof(dt_opencl_t)); dt_opencl_init(darktable.opencl, argc, argv); darktable.blendop = (dt_blendop_t *)malloc(sizeof(dt_blendop_t)); memset(darktable.blendop, 0, sizeof(dt_blendop_t)); dt_develop_blend_init(darktable.blendop); darktable.points = (dt_points_t *)malloc(sizeof(dt_points_t)); memset(darktable.points, 0, sizeof(dt_points_t)); dt_points_init(darktable.points, dt_get_num_threads()); // must come before mipmap_cache, because that one will need to access // image dimensions stored in here: darktable.image_cache = (dt_image_cache_t *)malloc(sizeof(dt_image_cache_t)); memset(darktable.image_cache, 0, sizeof(dt_image_cache_t)); dt_image_cache_init(darktable.image_cache); darktable.mipmap_cache = (dt_mipmap_cache_t *)malloc(sizeof(dt_mipmap_cache_t)); memset(darktable.mipmap_cache, 0, sizeof(dt_mipmap_cache_t)); dt_mipmap_cache_init(darktable.mipmap_cache); // The GUI must be initialized before the views, because the init() // functions of the views depend on darktable.control->accels_* to register // their keyboard accelerators if(init_gui) { darktable.gui = (dt_gui_gtk_t *)malloc(sizeof(dt_gui_gtk_t)); memset(darktable.gui,0,sizeof(dt_gui_gtk_t)); if(dt_gui_gtk_init(darktable.gui, argc, argv)) return 1; dt_bauhaus_init(); } else darktable.gui = NULL; darktable.view_manager = (dt_view_manager_t *)malloc(sizeof(dt_view_manager_t)); memset(darktable.view_manager, 0, sizeof(dt_view_manager_t)); dt_view_manager_init(darktable.view_manager); // load the darkroom mode plugins once: dt_iop_load_modules_so(); if(init_gui) { darktable.lib = (dt_lib_t *)malloc(sizeof(dt_lib_t)); memset(darktable.lib, 0, sizeof(dt_lib_t)); dt_lib_init(darktable.lib); dt_control_load_config(darktable.control); g_strlcpy(darktable.control->global_settings.dbname, filename, 512); // overwrite if relocated. } darktable.imageio = (dt_imageio_t *)malloc(sizeof(dt_imageio_t)); memset(darktable.imageio, 0, sizeof(dt_imageio_t)); dt_imageio_init(darktable.imageio); if(init_gui) { // Loading the keybindings char keyfile[DT_MAX_PATH_LEN]; // First dump the default keymapping snprintf(keyfile, DT_MAX_PATH_LEN, "%s/keyboardrc_default", datadir); gtk_accel_map_save(keyfile); // Removing extraneous semi-colons from the default keymap strip_semicolons_from_keymap(keyfile); // Then load any modified keys if available snprintf(keyfile, DT_MAX_PATH_LEN, "%s/keyboardrc", datadir); if(g_file_test(keyfile, G_FILE_TEST_EXISTS)) gtk_accel_map_load(keyfile); else gtk_accel_map_save(keyfile); // Save the default keymap if none is present // I doubt that connecting to dbus for darktable-cli makes sense darktable.dbus = dt_dbus_init(); // initialize undo struct darktable.undo = dt_undo_init(); // load image(s) specified on cmdline int id = 0; if(images_to_load) { // If only one image is listed, attempt to load it in darkroom gboolean load_in_dr = (g_slist_next(images_to_load) == NULL); GSList *p = images_to_load; while (p != NULL) { // don't put these function calls into MAX(), the macro will evaluate // it twice (and happily deadlock, in this particular case) int newid = dt_load_from_string((gchar*)p->data, load_in_dr); id = MAX(id, newid); p = g_slist_next(p); } if (!load_in_dr || id == 0) dt_ctl_switch_mode_to(DT_LIBRARY); g_slist_free(images_to_load); } else dt_ctl_switch_mode_to(DT_LIBRARY); } /* start the indexer background job */ dt_control_start_indexer(); if(darktable.unmuted & DT_DEBUG_MEMORY) { fprintf(stderr, "[memory] after successful startup\n"); dt_print_mem_usage(); } return 0; }