static void _lib_modulelist_populate_callback(gpointer instance, gpointer user_data) { dt_lib_module_t *self = (dt_lib_module_t *)user_data; if(!self || !(self->data)) return; GtkListStore *store; GtkTreeIter iter; GtkWidget *view=GTK_WIDGET(((dt_lib_modulelist_t*)self->data)->tree); GtkCellRenderer *pix_renderer,*fav_renderer,*text_renderer; GtkStyle *style=gtk_widget_get_style(view); store = gtk_list_store_new (NUM_COLS, GDK_TYPE_PIXBUF, G_TYPE_POINTER); gtk_tree_view_set_model (GTK_TREE_VIEW(view), GTK_TREE_MODEL(store)); g_object_unref (store); gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store), COL_MODULE, _lib_modulelist_gui_sort, NULL, NULL); gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store), COL_MODULE, GTK_SORT_ASCENDING); pix_renderer = gtk_cell_renderer_pixbuf_new (); g_object_set(pix_renderer,"cell-background-gdk",&style->bg[GTK_STATE_ACTIVE],NULL); fav_renderer = gtk_cell_renderer_pixbuf_new (); cairo_surface_t *fav_cst = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, ICON_SIZE, ICON_SIZE); cairo_t *fav_cr = cairo_create(fav_cst); cairo_set_source_rgb(fav_cr, 0.7,0.7,0.7); dtgtk_cairo_paint_modulegroup_favorites(fav_cr, 0, 0, ICON_SIZE, ICON_SIZE, 0); guchar* data = cairo_image_surface_get_data(fav_cst); dt_draw_cairo_to_gdk_pixbuf(data, ICON_SIZE, ICON_SIZE); ((dt_lib_modulelist_t*)self->data)->fav_pixbuf = gdk_pixbuf_new_from_data(data, GDK_COLORSPACE_RGB, TRUE, 8, ICON_SIZE, ICON_SIZE, cairo_image_surface_get_stride(fav_cst), NULL, NULL); g_object_set(fav_renderer,"cell-background-gdk",&style->bg[GTK_STATE_ACTIVE],NULL); g_object_set(fav_renderer,"width",gdk_pixbuf_get_width(((dt_lib_modulelist_t*)self->data)->fav_pixbuf),NULL); text_renderer = gtk_cell_renderer_text_new (); g_object_set(text_renderer,"cell-background-gdk",&style->bg[GTK_STATE_ACTIVE],NULL); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view),FALSE); gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(view),FALSE); gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(view),FALSE); GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); gtk_tree_selection_set_mode(selection, GTK_SELECTION_NONE); GtkTreeViewColumn *col; col = gtk_tree_view_get_column(GTK_TREE_VIEW(view), 0); if(col) gtk_tree_view_remove_column(GTK_TREE_VIEW(view), col); gtk_tree_view_insert_column_with_data_func (GTK_TREE_VIEW (view), 0, "favorite", fav_renderer, favorite_renderer_function, NULL,NULL); col = gtk_tree_view_get_column(GTK_TREE_VIEW(view), 1); if(col) gtk_tree_view_remove_column(GTK_TREE_VIEW(view), col); gtk_tree_view_insert_column_with_data_func (GTK_TREE_VIEW (view), 1, "image", pix_renderer, image_renderer_function, NULL,NULL); col = gtk_tree_view_get_column(GTK_TREE_VIEW(view), 2); if(col) gtk_tree_view_remove_column(GTK_TREE_VIEW(view), col); gtk_tree_view_insert_column_with_data_func (GTK_TREE_VIEW (view), 2, "name", text_renderer, text_renderer_function, NULL,NULL); /* go thru list of iop modules and add them to the list */ GList *modules = g_list_last(darktable.develop->iop); char datadir[PATH_MAX]; dt_loc_get_datadir(datadir, sizeof(datadir)); while(modules) { dt_iop_module_t *module = (dt_iop_module_t *)(modules->data); if(!dt_iop_is_hidden(module) && !(module->flags() & IOP_FLAGS_DEPRECATED) && module->multi_priority==0) { GdkPixbuf *pixbuf; char filename[PATH_MAX]; snprintf(filename, sizeof(filename), "%s/pixmaps/plugins/darkroom/%s.svg", datadir, module->op); pixbuf = load_image(filename); if(pixbuf) goto end; snprintf(filename, sizeof(filename), "%s/pixmaps/plugins/darkroom/%s.png", datadir, module->op); pixbuf = load_image(filename); if(pixbuf) goto end; snprintf(filename, sizeof(filename), "%s/pixmaps/plugins/darkroom/template.svg", datadir); pixbuf = load_image(filename); if(pixbuf) goto end; snprintf(filename, sizeof(filename), "%s/pixmaps/plugins/darkroom/template.png", datadir); pixbuf = load_image(filename); if(pixbuf) goto end; // wow, we could neither load the SVG nor the PNG files. something is f****d up. pixbuf = gdk_pixbuf_new_from_data(fallback_pixel, GDK_COLORSPACE_RGB, TRUE, 8, 1, 1, 4, NULL, NULL); end: gtk_list_store_append (store, &iter); gtk_list_store_set (store, &iter, COL_IMAGE, pixbuf, COL_MODULE,module, -1); g_object_unref (pixbuf); } modules = g_list_previous(modules); } }
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; }
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->dev); }
int dt_init(int argc, char *argv[], const int init_gui) { #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 new_xdg_data_dirs = g_strdup(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; 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; while(*c != '=' && c < keyval + strlen(keyval)) 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); } } #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(NULL); #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); // 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); } darktable.imageio = (dt_imageio_t *)calloc(1, sizeof(dt_imageio_t)); dt_imageio_init(darktable.imageio); 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,init_gui); #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; }
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,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->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_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; }
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; }
// maybe this should be (partly) in common/imageio.[c|h]? static void _lib_import_update_preview(GtkFileChooser *file_chooser, gpointer data) { GtkWidget *preview; char *filename; GdkPixbuf *pixbuf = NULL; gboolean have_preview = FALSE, no_preview_fallback = FALSE; preview = GTK_WIDGET(data); filename = gtk_file_chooser_get_preview_filename(file_chooser); if(!g_file_test(filename, G_FILE_TEST_IS_REGULAR)) { no_preview_fallback = TRUE; } else { // don't create dng thumbnails to avoid crashes in libtiff when these are hdr: char *c = filename + strlen(filename); while(c > filename && *c != '.') c--; if(!strcasecmp(c, ".dng")) no_preview_fallback = TRUE; } // unfortunately we can not use following, because frequently it uses wrong orientation // pixbuf = gdk_pixbuf_new_from_file_at_size(filename, 128, 128, NULL); have_preview = (pixbuf != NULL); if(!have_preview && !no_preview_fallback) { uint8_t *buffer = NULL; size_t size; char *mime_type = NULL; if(!dt_exif_get_thumbnail(filename, &buffer, &size, &mime_type)) { // Scale the image to the correct size GdkPixbuf *tmp; GdkPixbufLoader *loader = gdk_pixbuf_loader_new(); if (!gdk_pixbuf_loader_write(loader, buffer, size, NULL)) goto cleanup; if (!(tmp = gdk_pixbuf_loader_get_pixbuf(loader))) goto cleanup; float ratio = 1.0 * gdk_pixbuf_get_height(tmp) / gdk_pixbuf_get_width(tmp); int width = 128, height = 128 * ratio; pixbuf = gdk_pixbuf_scale_simple(tmp, width, height, GDK_INTERP_BILINEAR); have_preview = TRUE; cleanup: gdk_pixbuf_loader_close(loader, NULL); free(mime_type); free(buffer); g_object_unref(loader); // This should clean up tmp as well } } if(have_preview && !no_preview_fallback) { // get image orientation dt_image_t img = { 0 }; (void)dt_exif_read(&img, filename); // Rotate the image to the correct orientation GdkPixbuf *tmp = pixbuf; if(img.orientation == ORIENTATION_ROTATE_CCW_90_DEG) { tmp = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE); } else if(img.orientation == ORIENTATION_ROTATE_CW_90_DEG) { tmp = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_CLOCKWISE); } else if(img.orientation == ORIENTATION_ROTATE_180_DEG) { tmp = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_UPSIDEDOWN); } if(pixbuf != tmp) { g_object_unref(pixbuf); pixbuf = tmp; } } if(no_preview_fallback || !have_preview) { /* load the dt logo as a brackground */ char dtlogo[PATH_MAX] = { 0 }; char datadir[PATH_MAX] = { 0 }; char *logo; dt_logo_season_t season = get_logo_season(); if(season != DT_LOGO_SEASON_NONE) logo = g_strdup_printf("%%s/pixmaps/idbutton-%d.svg", (int)season); else logo = g_strdup("%s/pixmaps/idbutton.svg"); dt_loc_get_datadir(datadir, sizeof(datadir)); snprintf(dtlogo, sizeof(dtlogo), logo, datadir); g_free(logo); RsvgHandle *svg = rsvg_handle_new_from_file(dtlogo, NULL); if(svg) { cairo_surface_t *surface; cairo_t *cr; RsvgDimensionData dimension; rsvg_handle_get_dimensions(svg, &dimension); float svg_size = MAX(dimension.width, dimension.height); float final_size = 128; float factor = final_size / svg_size; float final_width = dimension.width * factor * darktable.gui->ppd, final_height = dimension.height * factor * darktable.gui->ppd; int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, final_width); guint8 *image_buffer = (guint8 *)calloc(stride * final_height, sizeof(guint8)); surface = dt_cairo_image_surface_create_for_data(image_buffer, CAIRO_FORMAT_ARGB32, final_width, final_height, stride); if(cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) { free(image_buffer); image_buffer = NULL; } else { cr = cairo_create(surface); cairo_scale(cr, factor, factor); rsvg_handle_render_cairo(svg, cr); cairo_destroy(cr); cairo_surface_flush(surface); pixbuf = gdk_pixbuf_get_from_surface(surface, 0, 0, final_width / darktable.gui->ppd, final_height / darktable.gui->ppd); cairo_surface_destroy(surface); free(image_buffer); } g_object_unref(svg); } have_preview = TRUE; } if(have_preview) gtk_image_set_from_pixbuf(GTK_IMAGE(preview), pixbuf); if(pixbuf) g_object_unref(pixbuf); g_free(filename); gtk_file_chooser_set_preview_widget_active(file_chooser, have_preview); }
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 (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()); it = g_list_next(it); } 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 (GTK_WIDGET (d->width)); dt_gui_key_accel_block_on_focus (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); }
void gui_init(dt_lib_module_t *self) { char filename[PATH_MAX] = { 0 }; char datadir[PATH_MAX] = { 0 }; /* initialize ui widgets */ dt_lib_darktable_t *d = (dt_lib_darktable_t *)g_malloc0(sizeof(dt_lib_darktable_t)); self->data = (void *)d; /* create drawing area */ self->widget = gtk_event_box_new(); /* connect callbacks */ g_signal_connect(G_OBJECT(self->widget), "draw", G_CALLBACK(_lib_darktable_draw_callback), self); g_signal_connect(G_OBJECT(self->widget), "button-press-event", G_CALLBACK(_lib_darktable_button_press_callback), self); /* create a cairo surface of dt icon */ char *logo; dt_logo_season_t season = get_logo_season(); if(season != DT_LOGO_SEASON_NONE) logo = g_strdup_printf("%%s/pixmaps/idbutton-%d.%%s", (int)season); else logo = g_strdup("%s/pixmaps/idbutton.%s"); dt_loc_get_datadir(datadir, sizeof(datadir)); snprintf(filename, sizeof(filename), logo, datadir, "svg"); // first we try the SVG { GError *error = NULL; RsvgHandle *svg = rsvg_handle_new_from_file(filename, &error); if(!svg || error) { fprintf(stderr, "warning: can't load darktable logo from SVG file `%s', falling back to PNG version\n%s\n", filename, error->message); g_error_free(error); error = NULL; goto png_fallback; } cairo_surface_t *surface; cairo_t *cr; RsvgDimensionData dimension; rsvg_handle_get_dimensions(svg, &dimension); int width = DT_PIXEL_APPLY_DPI(dimension.width) * darktable.gui->ppd, height = DT_PIXEL_APPLY_DPI(dimension.height) * darktable.gui->ppd; int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); d->image_buffer = (guint8 *)calloc(stride * height, sizeof(guint8)); surface = dt_cairo_image_surface_create_for_data(d->image_buffer, CAIRO_FORMAT_ARGB32, width, height, stride); if(cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) { free(d->image_buffer); d->image_buffer = NULL; g_object_unref(svg); fprintf(stderr, "warning: can't load darktable logo from SVG file `%s', falling back to PNG version\n", filename); goto png_fallback; } cr = cairo_create(surface); cairo_scale(cr, darktable.gui->dpi_factor, darktable.gui->dpi_factor); rsvg_handle_render_cairo(svg, cr); cairo_destroy(cr); cairo_surface_flush(surface); d->image = surface; g_object_unref(svg); } goto done; png_fallback: // let's fall back to the PNG { cairo_surface_t *surface; cairo_t *cr; snprintf(filename, sizeof(filename), logo, datadir, "png"); surface = cairo_image_surface_create_from_png(filename); if(cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) { fprintf(stderr, "warning: can't load darktable logo from PNG file `%s'\n", filename); d->image = NULL; goto done; } int png_width = cairo_image_surface_get_width(surface), png_height = cairo_image_surface_get_height(surface); // blow up the PNG. Ugly, but at least it has the correct size afterwards :-/ int width = DT_PIXEL_APPLY_DPI(png_width) * darktable.gui->ppd, height = DT_PIXEL_APPLY_DPI(png_height) * darktable.gui->ppd; int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); d->image_buffer = (guint8 *)calloc(stride * height, sizeof(guint8)); d->image = dt_cairo_image_surface_create_for_data(d->image_buffer, CAIRO_FORMAT_ARGB32, width, height, stride); if(cairo_surface_status(d->image) != CAIRO_STATUS_SUCCESS) { free(d->image_buffer); d->image_buffer = NULL; cairo_surface_destroy(surface); fprintf(stderr, "warning: can't load darktable logo from PNG file `%s'\n", filename); d->image = NULL; goto done; } cr = cairo_create(d->image); cairo_rectangle(cr, 0, 0, width, height); cairo_scale(cr, darktable.gui->dpi_factor, darktable.gui->dpi_factor); cairo_set_source_surface(cr, surface, 0, 0); cairo_fill(cr); cairo_destroy(cr); cairo_surface_flush(d->image); cairo_surface_destroy(surface); } done: g_free(logo); d->image_width = d->image ? dt_cairo_image_surface_get_width(d->image) : 0; d->image_height = d->image ? dt_cairo_image_surface_get_height(d->image) : 0; /* set size of drawing area */ gtk_widget_set_size_request(self->widget, d->image_width + (int)DT_PIXEL_APPLY_DPI(180), d->image_height + (int)DT_PIXEL_APPLY_DPI(8)); }
static void get_language_names(GList *languages) { #ifdef HAVE_ISO_CODES JsonReader *reader = NULL; JsonParser *parser = NULL; GError *error = NULL; #if defined(_WIN32) && !defined(MSYS2_INSTALL) // TODO: add osx? char datadir[PATH_MAX] = { 0 }; dt_loc_get_datadir(datadir, sizeof(datadir)); char *filename = g_build_filename(datadir, "..", "iso-codes", "json", "iso_639-2.json", NULL); #else char *filename = g_build_filename(ISO_CODES_LOCATION, "iso_639-2.json", NULL); #endif if(!g_file_test(filename, G_FILE_TEST_EXISTS)) { fprintf(stderr, "[l10n] error: can't open iso-codes file `%s'\n" " there won't be nicely translated language names in the preferences.\n", filename); goto end; } #if defined(_WIN32) && !defined(MSYS2_INSTALL) // TODO: add osx? // on windows we are shipping the translations of iso-codes along ours char *localedir = g_build_filename(datadir, "..", "locale", NULL); bindtextdomain("iso_639", localedir); g_free(localedir); #else bindtextdomain("iso_639", ISO_CODES_LOCALEDIR); #endif bind_textdomain_codeset("iso_639", "UTF-8"); parser = json_parser_new(); if(!json_parser_load_from_file(parser, filename, &error)) { fprintf(stderr, "[l10n] error: parsing json from `%s' failed\n%s\n", filename, error->message); goto end; } // go over the json JsonNode *root = json_parser_get_root(parser); if(!root) { fprintf(stderr, "[l10n] error: can't get root node of `%s'\n", filename); goto end; } reader = json_reader_new(root); if(!json_reader_read_member(reader, "639-2")) { fprintf(stderr, "[l10n] error: unexpected layout of `%s'\n", filename); goto end; } if(!json_reader_is_array(reader)) { fprintf(stderr, "[l10n] error: unexpected layout of `%s'\n", filename); goto end; } int n_elements = json_reader_count_elements(reader); for(int i = 0; i < n_elements; i++) { json_reader_read_element(reader, i); if(!json_reader_is_object(reader)) { fprintf(stderr, "[l10n] error: unexpected layout of `%s' (element %d)\n", filename, i); goto end; } const char *alpha_2 = NULL, *alpha_3 = NULL, *name = NULL; if(json_reader_read_member(reader, "alpha_2")) alpha_2 = json_reader_get_string_value(reader); json_reader_end_member(reader); // alpha_2 if(json_reader_read_member(reader, "alpha_3")) alpha_3 = json_reader_get_string_value(reader); json_reader_end_member(reader); // alpha_3 if(json_reader_read_member(reader, "name")) name = json_reader_get_string_value(reader); json_reader_end_member(reader); // name if(name && (alpha_2 || alpha_3)) { // check if alpha_2 or alpha_3 is in our translations for(GList *iter = languages; iter; iter = g_list_next(iter)) { dt_l10n_language_t *language = (dt_l10n_language_t *)iter->data; if(!g_strcmp0(language->base_code, alpha_2) || !g_strcmp0(language->base_code, alpha_3)) { // code taken in parts from GIMP's gimplanguagestore-parser.c g_setenv("LANGUAGE", language->code, TRUE); setlocale (LC_ALL, language->code); char *localized_name = g_strdup(dgettext("iso_639", name)); /* If original and localized names are the same for other than English, * maybe localization failed. Try now in the main dialect. */ if(g_strcmp0(name, localized_name) == 0 && g_strcmp0(language->code, language->base_code) != 0) { g_free(localized_name); g_setenv("LANGUAGE", language->base_code, TRUE); setlocale (LC_ALL, language->base_code); localized_name = g_strdup(dgettext("iso_639", name)); } /* there might be several language names; use the first one */ char *semicolon = strchr(localized_name, ';'); if(semicolon) { char *tmp = localized_name; localized_name = g_strndup(localized_name, semicolon - localized_name); g_free(tmp); } // we initialize the name to the language code to have something on systems lacking iso-codes, so free it! g_free(language->name); language->name = g_strdup_printf("%s (%s)%s", localized_name, language->code, language->is_default ? " *" : ""); g_free(localized_name); // we can't break out of the loop here. at least pt is in our list twice! } } } else fprintf(stderr, "[l10n] error: element %d has no name, skipping\n", i); json_reader_end_element(reader); } json_reader_end_member(reader); // 639-2 end: // cleanup g_free(filename); if(error) g_error_free(error); if(reader) g_object_unref(reader); if(parser) g_object_unref(parser); #endif // HAVE_ISO_CODES }
dt_l10n_t *dt_l10n_init(gboolean init_list) { dt_l10n_t *result = (dt_l10n_t *)calloc(1, sizeof(dt_l10n_t)); result->selected = -1; result->sys_default = -1; char *ui_lang = dt_conf_get_string("ui_last/gui_language"); const char *old_env = g_getenv("LANGUAGE"); #if defined(_WIN32) // get the default locale if no language preference was specified in the config file if(!ui_lang || !*ui_lang) { 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(ui_lang); ui_lang = g_strdup(langLocale); } } } #endif // defined (_WIN32) // prepare the list of available gui translations from which the user can pick in prefs if(init_list) { dt_l10n_language_t *selected = NULL; dt_l10n_language_t *sys_default = NULL; dt_l10n_language_t *language = (dt_l10n_language_t *)calloc(1, sizeof(dt_l10n_language_t)); language->code = g_strdup("C"); language->base_code = g_strdup("C"); language->name = g_strdup("English"); result->languages = g_list_append(result->languages, language); if(g_strcmp0(ui_lang, "C") == 0) selected = language; const gchar * const * default_languages = g_get_language_names(); #ifdef _WIN32 char datadir[PATH_MAX] = { 0 }; dt_loc_get_datadir(datadir, sizeof(datadir)); char *localedir = g_build_filename(datadir, "..", "locale", NULL); #else char * localedir = g_strdup(DARKTABLE_LOCALEDIR); #endif GDir *dir = g_dir_open(localedir, 0, NULL); if(dir) { const gchar *locale; while((locale = g_dir_read_name(dir))) { gchar *testname = g_build_filename(localedir, locale, "LC_MESSAGES", GETTEXT_PACKAGE ".mo", NULL); if(g_file_test(testname, G_FILE_TEST_EXISTS)) { language = (dt_l10n_language_t *)calloc(1, sizeof(dt_l10n_language_t)); result->languages = g_list_prepend(result->languages, language); // some languages have a regional part in the filename, we don't want that for name lookup char *delimiter = strchr(locale, '_'); if(delimiter) language->base_code = g_strndup(locale, delimiter - locale); else language->base_code = g_strdup(locale); delimiter = strchr(language->base_code, '@'); if(delimiter) { char *tmp = language->base_code; language->base_code = g_strndup(language->base_code, delimiter - language->base_code); g_free(tmp); } // check if this is the system default if(sys_default == NULL) { for(const gchar * const * iter = default_languages; *iter; iter++) { if(g_strcmp0(*iter, locale) == 0) { language->is_default = TRUE; sys_default = language; break; } } } language->code = g_strdup(locale); language->name = g_strdup_printf("%s%s", locale, language->is_default ? " *" : ""); if(g_strcmp0(ui_lang, language->code) == 0) selected = language; } g_free(testname); } g_dir_close(dir) ; } else fprintf(stderr, "[l10n] error: can't open directory `%s'\n", localedir); // now try to find language names and translations! get_language_names(result->languages); // set the requested gui language. // this has to happen before sorting the list as the sort result may depend on the language. set_locale(ui_lang, old_env); // sort the list of languages result->languages = g_list_sort(result->languages, sort_languages); // find the index of the selected and default languages int i = 0; for(GList *iter = result->languages; iter; iter = g_list_next(iter)) { if(iter->data == sys_default) result->sys_default = i; if(iter->data == selected) result->selected = i; i++; } if(selected == NULL) result->selected = result->sys_default; g_free(localedir); } else set_locale(ui_lang, old_env); g_free(ui_lang); return result; }
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; }
void dt_opencl_init(dt_opencl_t *cl, const int argc, char *argv[]) { dt_pthread_mutex_init(&cl->lock, NULL); cl->inited = 0; cl->enabled = 0; cl->dlocl = NULL; int exclude_opencl = 0; // user selectable parameter defines minimum requirement on GPU memory // default is 768MB // values below 256 will be (re)set to 256 const int opencl_memory_requirement = max(256, dt_conf_get_int("opencl_memory_requirement")); dt_conf_set_int("opencl_memory_requirement", opencl_memory_requirement); for(int k=0; k<argc; k++) if(!strcmp(argv[k], "--disable-opencl")) { dt_print(DT_DEBUG_OPENCL, "[opencl_init] do not try to find and use an opencl runtime library due to explicit user request\n"); exclude_opencl = 1; } if(exclude_opencl) goto finally; // look for explicit definition of opencl_runtime library in preferences const char *library = dt_conf_get_string("opencl_library"); dt_print(DT_DEBUG_OPENCL, "[opencl_init] trying to load opencl library: '%s'\n", library && strlen(library) != 0 ? library : "<system default>"); // dynamically load opencl runtime if(!dt_dlopencl_init(library, &cl->dlocl)) { dt_print(DT_DEBUG_OPENCL, "[opencl_init] no working opencl library found. Continue with opencl disabled\n"); goto finally; } else { dt_print(DT_DEBUG_OPENCL, "[opencl_init] opencl library '%s' found on your system and loaded\n", cl->dlocl->library); } cl_int err; cl_platform_id all_platforms[DT_OPENCL_MAX_PLATFORMS]; cl_uint all_num_devices[DT_OPENCL_MAX_PLATFORMS]; cl_uint num_platforms = DT_OPENCL_MAX_PLATFORMS; err = (cl->dlocl->symbols->dt_clGetPlatformIDs) (DT_OPENCL_MAX_PLATFORMS, all_platforms, &num_platforms); if(err != CL_SUCCESS) { dt_print(DT_DEBUG_OPENCL, "[opencl_init] could not get platforms: %d\n", err); goto finally; } if(num_platforms == 0) { dt_print(DT_DEBUG_OPENCL, "[opencl_init] no opencl platform available\n"); goto finally; } for(int n=0; n < num_platforms; n++) { cl_platform_id platform = all_platforms[n]; // get the number of GPU devices available to the platforms // the other common option is CL_DEVICE_TYPE_GPU/CPU (but the latter doesn't work with the nvidia drivers) err = (cl->dlocl->symbols->dt_clGetDeviceIDs)(platform, CL_DEVICE_TYPE_ALL, 0, NULL, &(all_num_devices[n])); if(err != CL_SUCCESS) { dt_print(DT_DEBUG_OPENCL, "[opencl_init] could not get device id size: %d\n", err); goto finally; } } cl_uint num_devices = 0; for(int n=0; n < num_platforms; n++) num_devices += all_num_devices[n]; // create the device list cl->dev = (dt_opencl_device_t *)malloc(sizeof(dt_opencl_device_t)*num_devices); cl_device_id *devices = (cl_device_id *)malloc(sizeof(cl_device_id)*num_devices); cl_device_id *devs = devices; for(int n=0; n < num_platforms; n++) { cl_platform_id platform = all_platforms[n]; err = (cl->dlocl->symbols->dt_clGetDeviceIDs)(platform, CL_DEVICE_TYPE_ALL, all_num_devices[n], devs, NULL); if(err != CL_SUCCESS) { dt_print(DT_DEBUG_OPENCL, "[opencl_init] could not get devices list: %d\n", err); goto finally; } devs += all_num_devices[n]; } dt_print(DT_DEBUG_OPENCL, "[opencl_init] found %d device%s\n", num_devices, num_devices > 1 ? "s" : ""); int dev = 0; for(int k=0; k<num_devices; k++) { memset(cl->dev[dev].program_used, 0x0, sizeof(int)*DT_OPENCL_MAX_PROGRAMS); memset(cl->dev[dev].kernel_used, 0x0, sizeof(int)*DT_OPENCL_MAX_KERNELS); cl->dev[dev].eventlist = NULL; cl->dev[dev].eventtags = NULL; cl->dev[dev].numevents = 0; cl->dev[dev].eventsconsolidated = 0; cl->dev[dev].maxevents = 0; cl->dev[dev].lostevents = 0; cl->dev[dev].summary=CL_COMPLETE; cl->dev[dev].used_global_mem = 0; cl_device_id devid = cl->dev[dev].devid = devices[k]; char infostr[1024]; size_t infoint; size_t infointtab[1024]; cl_device_type type; cl_bool image_support = 0; // test GPU memory and image support: (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DEVICE_NAME, sizeof(infostr), &infostr, NULL); (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DEVICE_TYPE, sizeof(cl_device_type), &type, NULL); (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DEVICE_IMAGE_SUPPORT, sizeof(cl_bool), &image_support, NULL); (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DEVICE_IMAGE2D_MAX_HEIGHT, sizeof(size_t), &(cl->dev[dev].max_image_height), NULL); (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DEVICE_IMAGE2D_MAX_WIDTH, sizeof(size_t), &(cl->dev[dev].max_image_width), NULL); (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DEVICE_MAX_MEM_ALLOC_SIZE, sizeof(cl_ulong), &(cl->dev[dev].max_mem_alloc), NULL); if(type == CL_DEVICE_TYPE_CPU) { dt_print(DT_DEBUG_OPENCL, "[opencl_init] discarding CPU device %d `%s' as it will not deliver any performance gain.\n", k, infostr); continue; } if(!image_support) { dt_print(DT_DEBUG_OPENCL, "[opencl_init] discarding device %d `%s' due to missing image support.\n", k, infostr); continue; } (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DEVICE_GLOBAL_MEM_SIZE, sizeof(cl_ulong), &(cl->dev[dev].max_global_mem), NULL); if(cl->dev[dev].max_global_mem < opencl_memory_requirement*1024*1024) { dt_print(DT_DEBUG_OPENCL, "[opencl_init] discarding device %d `%s' due to insufficient global memory (%luMB).\n", k, infostr, cl->dev[dev].max_global_mem/1024/1024); continue; } dt_print(DT_DEBUG_OPENCL, "[opencl_init] device %d `%s' supports image sizes of %zd x %zd\n", k, infostr, cl->dev[dev].max_image_width, cl->dev[dev].max_image_height); dt_print(DT_DEBUG_OPENCL, "[opencl_init] device %d `%s' allows GPU memory allocations of up to %luMB\n", k, infostr, cl->dev[dev].max_mem_alloc/1024/1024); if(darktable.unmuted & DT_DEBUG_OPENCL) { printf("[opencl_init] device %d: %s \n", k, infostr); printf(" GLOBAL_MEM_SIZE: %.0fMB\n", (double)cl->dev[dev].max_global_mem/1024.0/1024.0); (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DEVICE_MAX_WORK_GROUP_SIZE, sizeof(infoint), &infoint, NULL); printf(" MAX_WORK_GROUP_SIZE: %zd\n", infoint); (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, sizeof(infoint), &infoint, NULL); printf(" MAX_WORK_ITEM_DIMENSIONS: %zd\n", infoint); printf(" MAX_WORK_ITEM_SIZES: [ "); (cl->dlocl->symbols->dt_clGetDeviceInfo)(devid, CL_DEVICE_MAX_WORK_ITEM_SIZES, sizeof(infointtab), infointtab, NULL); for (int i=0; i<infoint; i++) printf("%zd ", infointtab[i]); printf("]\n"); } dt_pthread_mutex_init(&cl->dev[dev].lock, NULL); cl->dev[dev].context = (cl->dlocl->symbols->dt_clCreateContext)(0, 1, &devid, NULL, NULL, &err); if(err != CL_SUCCESS) { dt_print(DT_DEBUG_OPENCL, "[opencl_init] could not create context for device %d: %d\n", k, err); goto finally; } // create a command queue for first device the context reported cl->dev[dev].cmd_queue = (cl->dlocl->symbols->dt_clCreateCommandQueue)(cl->dev[dev].context, devid, (darktable.unmuted & DT_DEBUG_PERF) ? CL_QUEUE_PROFILING_ENABLE : 0, &err); if(err != CL_SUCCESS) { dt_print(DT_DEBUG_OPENCL, "[opencl_init] could not create command queue for device %d: %d\n", k, err); goto finally; } char dtpath[1024], filename[1024], programname[1024]; dt_loc_get_datadir(dtpath, 1024); snprintf(filename, 1024, "%s/kernels/programs.conf", dtpath); // now load all darktable cl kernels. // TODO: compile as a job? FILE *f = fopen(filename, "rb"); if(f) { while(!feof(f)) { int rd = fscanf(f, "%[^\n]\n", programname); if(rd != 1) continue; // remove comments: for(int k=0; k<strlen(programname); k++) if(programname[k] == '#') { programname[k] = '\0'; for(int l=k-1; l>=0; l--) { if (programname[l] == ' ') programname[l] = '\0'; else break; } break; } if(programname[0] == '\0') continue; snprintf(filename, 1024, "%s/kernels/%s", dtpath, programname); dt_print(DT_DEBUG_OPENCL, "[opencl_init] compiling program `%s' ..\n", programname); const int prog = dt_opencl_load_program(dev, filename); if(dt_opencl_build_program(dev, prog)) { dt_print(DT_DEBUG_OPENCL, "[opencl_init] failed to compile program `%s'!\n", programname); goto finally; } } fclose(f); } else { dt_print(DT_DEBUG_OPENCL, "[opencl_init] could not open `%s'!\n", filename); goto finally; } ++dev; } free(devices); if(dev > 0) { dt_print(DT_DEBUG_OPENCL, "[opencl_init] successfully initialized.\n"); cl->num_devs = dev; cl->inited = 1; cl->enabled = dt_conf_get_bool("opencl"); } else { dt_print(DT_DEBUG_OPENCL, "[opencl_init] no suitable devices found.\n"); } finally: dt_print(DT_DEBUG_OPENCL, "[opencl_init] FINALLY: opencl is %sAVAILABLE on this system.\n", cl->inited ? "" : "NOT "); dt_print(DT_DEBUG_OPENCL, "[opencl_init] initial status of opencl enabled flag is %s.\n", cl->enabled ? "ON" : "OFF"); return; }
void gui_init(struct dt_iop_module_t *self) { self->gui_data = malloc(sizeof(dt_iop_zonesystem_gui_data_t)); dt_iop_zonesystem_gui_data_t *g = (dt_iop_zonesystem_gui_data_t *)self->gui_data; g->in_preview_buffer = g->out_preview_buffer = NULL; g->is_dragging = FALSE; g->hilite_zone = FALSE; g->preview_width=g->preview_height = 0; g->mouse_over_output_zones = FALSE; dt_pthread_mutex_init(&g->lock, NULL); self->widget = gtk_vbox_new (FALSE,DT_GUI_IOP_MODULE_CONTROL_SPACING); /* create the zone preview widget */ const int panel_width = dt_conf_get_int("panel_width") * 0.8; g->preview = gtk_drawing_area_new(); g_signal_connect (G_OBJECT (g->preview), "expose-event", G_CALLBACK (dt_iop_zonesystem_preview_expose), self); gtk_widget_add_events (GTK_WIDGET (g->preview), GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK); gtk_widget_set_size_request(g->preview, panel_width, panel_width); /* create the zonesystem bar widget */ g->zones = gtk_drawing_area_new(); g_object_set (GTK_OBJECT(g->zones), "tooltip-text", _("lightness zones\nuse mouse scrollwheel to change the number of zones\nleft-click on a border to create a marker\nright-click on a marker to delete it"), (char *)NULL); g_signal_connect (G_OBJECT (g->zones), "expose-event", G_CALLBACK (dt_iop_zonesystem_bar_expose), self); g_signal_connect (G_OBJECT (g->zones), "motion-notify-event", G_CALLBACK (dt_iop_zonesystem_bar_motion_notify), self); g_signal_connect (G_OBJECT (g->zones), "leave-notify-event", G_CALLBACK (dt_iop_zonesystem_bar_leave_notify), self); g_signal_connect (G_OBJECT (g->zones), "button-press-event", G_CALLBACK (dt_iop_zonesystem_bar_button_press), self); g_signal_connect (G_OBJECT (g->zones), "button-release-event", G_CALLBACK (dt_iop_zonesystem_bar_button_release), self); g_signal_connect (G_OBJECT (g->zones), "scroll-event", G_CALLBACK (dt_iop_zonesystem_bar_scrolled), self); gtk_widget_add_events (GTK_WIDGET (g->zones), GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK); gtk_widget_set_size_request(g->zones, -1, DT_PIXEL_APPLY_DPI(40)); gtk_box_pack_start (GTK_BOX (self->widget),g->preview,TRUE,TRUE,0); gtk_box_pack_start (GTK_BOX (self->widget),g->zones,TRUE,TRUE,0); /* add signal handler for preview pipe finish to redraw the preview */ dt_control_signal_connect(darktable.signals, DT_SIGNAL_DEVELOP_PREVIEW_PIPE_FINISHED, G_CALLBACK(_iop_zonesystem_redraw_preview_callback), self); /* load the dt logo as a brackground */ g->image = NULL; g->image_buffer = NULL; g->image_width = 0; g->image_height = 0; char filename[PATH_MAX]; char datadir[PATH_MAX]; const char *logo = is_it_xmas()?"%s/pixmaps/idbutton-2.svg":"%s/pixmaps/idbutton.svg"; dt_loc_get_datadir(datadir, sizeof(datadir)); snprintf(filename, sizeof(filename), logo, datadir); RsvgHandle *svg = rsvg_handle_new_from_file(filename, NULL); if(svg) { cairo_surface_t *surface; cairo_t *cr; RsvgDimensionData dimension; rsvg_handle_get_dimensions(svg, &dimension); float svg_size = MAX(dimension.width, dimension.height); float final_size = panel_width * 0.75; float factor = final_size / svg_size; float final_width = dimension.width * factor, final_height = dimension.height * factor; int stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, final_width); g->image_buffer = (guint8 *)calloc(stride * final_height, sizeof(guint8)); surface = cairo_image_surface_create_for_data(g->image_buffer, CAIRO_FORMAT_ARGB32, final_width, final_height, stride); if(cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) { free(g->image_buffer); g->image_buffer = NULL; } else { cr = cairo_create(surface); cairo_scale(cr, factor, factor); rsvg_handle_render_cairo(svg, cr); cairo_surface_flush(surface); g->image = surface; g->image_width = final_width; g->image_height = final_height; } g_object_unref(svg); } }