// look for app_versions.xml file in project dir. // If find, get app versions from there, // and use "anonymous platform" mechanism for this project // void CLIENT_STATE::check_anonymous() { unsigned int i; char dir[256], path[256]; FILE* f; int retval; for (i=0; i<projects.size(); i++) { PROJECT* p = projects[i]; get_project_dir(p, dir, sizeof(dir)); sprintf(path, "%s/%s", dir, APP_INFO_FILE_NAME); f = fopen(path, "r"); if (!f) continue; msg_printf(p, MSG_INFO, "Found %s; using anonymous platform", APP_INFO_FILE_NAME ); p->anonymous_platform = true; // flag as anonymous even if can't parse file retval = parse_app_info(p, f); if (retval) { msg_printf_notice(p, false, "http://boinc.berkeley.edu/manager_links.php?target=notice&controlid=app_info", "%s", _("Syntax error in app_info.xml") ); } fclose(f); } }
// delete current sym links. // This is done when parsing scheduler reply, // to ensure that we get rid of sym links for // project files no longer in use // void PROJECT::delete_project_file_symlinks() { unsigned int i; char project_dir[256], path[MAXPATHLEN]; get_project_dir(this, project_dir, sizeof(project_dir)); for (i=0; i<project_files.size(); i++) { FILE_REF& fref = project_files[i]; sprintf(path, "%s/%s", project_dir, fref.open_name); delete_project_owned_file(path, false); } }
int remove_project_dir(PROJECT& p) { char buf[1024]; int retval; get_project_dir(&p, buf, sizeof(buf)); retval = client_clean_out_dir(buf, "remove project dir"); if (retval) { msg_printf(&p, MSG_INTERNAL_ERROR, "Can't delete file %s", boinc_failed_file); return retval; } return remove_project_owned_dir(buf); }
/* Export in the iwb format. */ void export_iwb (gchar *iwb_location) { const gchar *tmpdir = g_get_tmp_dir (); gchar *images = "images"; gchar *background_image = get_background_image(); gchar *project_name = get_project_name (); gchar *ardesia_tmp_dir = g_build_filename (tmpdir, PACKAGE_NAME, (gchar *) 0); gchar *project_tmp_dir = g_build_filename (ardesia_tmp_dir, project_name, (gchar *) 0); gchar *img_dir_path = g_build_filename (project_tmp_dir, images, (gchar *) 0); gchar *first_savepoint_file = g_strdup_printf ("%s%s%s_2_vellum.png", img_dir_path, G_DIR_SEPARATOR_S, PACKAGE_NAME); /* if exist the file I continue to save */ if ((file_exists(first_savepoint_file)) || (background_image)) { gchar *iwb_file = (gchar *) NULL; gchar *content_filename = "content.xml"; gchar *content_filepath = g_build_filename (project_tmp_dir, content_filename, (gchar *) 0); /* If the iwb location is null means that it is a new project. */ if (iwb_location == NULL) { /* It will be putted in the project dir. */ gchar *extension = "iwb"; gchar *iwb_name = g_strdup_printf("%s.%s", get_project_name (), extension); /* The zip file is the iwb file located in the ardesia workspace. */ iwb_file = g_build_filename (get_project_dir (), iwb_name, (gchar *) 0); g_free(iwb_name); } else { g_remove (iwb_location); iwb_file = g_strdup_printf ("%s", iwb_location); } g_remove (content_filepath); create_xml_content (content_filepath, img_dir_path, background_image); create_iwb (iwb_file, project_tmp_dir, "images", content_filename); /* Add to the list of the artefacts created in the session. */ add_artifact (iwb_file); g_free (iwb_file); g_free (content_filepath); } g_free (first_savepoint_file); g_free (ardesia_tmp_dir); g_free (project_tmp_dir); g_free (img_dir_path); }
// Gets the pathname of a file // void get_pathname(FILE_INFO* fip, char* path, int len) { PROJECT* p = fip->project; char buf[1024]; // for testing purposes, it's handy to allow a FILE_INFO without // an associated PROJECT. // if (p) { #ifdef ENABLE_AUTO_UPDATE if (fip->is_auto_update_file) { boinc_version_dir(*p, gstate.auto_update.version, buf); } else { get_project_dir(p, buf, sizeof(buf)); } #else get_project_dir(p, buf, sizeof(buf)); #endif snprintf(path, len, "%s/%s", buf, fip->name); } else { strlcpy(path, fip->name, len); } }
// write symlinks for project files. // Note: it's conceivable that one physical file // has several logical names, so try them all // int PROJECT::write_symlink_for_project_file(FILE_INFO* fip) { char project_dir[256], link_path[MAXPATHLEN], file_path[MAXPATHLEN]; unsigned int i; get_project_dir(this, project_dir, sizeof(project_dir)); for (i=0; i<project_files.size(); i++) { FILE_REF& fref = project_files[i]; if (fref.file_info != fip) continue; sprintf(link_path, "%s/%s", project_dir, fref.open_name); sprintf(file_path, "%s/%s", project_dir, fip->name); make_soft_link(this, link_path, file_path); } return 0; }
void check_app_config() { char dir[256], path[MAXPATHLEN]; FILE* f; for (unsigned int i=0; i<gstate.projects.size(); i++) { PROJECT* p = gstate.projects[i]; get_project_dir(p, dir, sizeof(dir)); sprintf(path, "%s/%s", dir, APP_CONFIG_FILE_NAME); f = boinc_fopen(path, "r"); if (!f) continue; msg_printf(p, MSG_INFO, "Found %s", APP_CONFIG_FILE_NAME ); int retval = p->app_configs.parse_file(f, p); if (!retval) { p->app_configs.config_app_versions(p); } fclose(f); } }
// Create the directory for the project p // int make_project_dir(PROJECT& p) { char buf[1024]; int retval; boinc_mkdir(PROJECTS_DIR); #ifndef _WIN32 mode_t old_mask; if (g_use_sandbox) { old_mask = umask(2); // Allow writing by group chmod(PROJECTS_DIR, S_IRUSR|S_IWUSR|S_IXUSR |S_IRGRP|S_IWGRP|S_IXGRP ); umask(old_mask); // Only user boinc_master and group boinc_project can access // project directories, to keep authenticators private set_to_project_group(PROJECTS_DIR); } #endif get_project_dir(&p, buf, sizeof(buf)); retval = boinc_mkdir(buf); #ifndef _WIN32 if (g_use_sandbox) { old_mask = umask(2); // Contents of projects directory must be world-readable so BOINC Client can read // files written by projects which have user boinc_project and group boinc_project chmod(buf, S_IRUSR|S_IWUSR|S_IXUSR |S_IRGRP|S_IWGRP|S_IXGRP |S_IROTH|S_IXOTH ); umask(old_mask); set_to_project_group(buf); } #endif return retval; }
void boinc_version_dir(PROJECT& p, VERSION_INFO& vi, char* buf) { char projdir[1024]; get_project_dir(&p, projdir, sizeof(projdir)); sprintf(buf, "%s/boinc_version_%d_%d_%d", projdir, vi.major, vi.minor, vi.release); }
/// Start a task in a slot directory. /// This includes setting up soft links, /// passing preferences, and starting the process. /// /// Current dir is top-level Synecdoche dir. /// /// \post /// - If any error occurs /// - #task_state is #PROCESS_COULDNT_START /// - CLIENT_STATE::report_result_error() is called /// - else /// - #task_state is #PROCESS_EXECUTING /// /// \return 0 on success, nonzero otherwise. int ACTIVE_TASK::start() { char exec_name[256], exec_path[256]; unsigned int i; FILE_REF fref; int retval; // F*** goto, need to define some variables here instead of where they are used! std::ostringstream err_stream; #ifdef _WIN32 std::string cmd_line; std::string slotdirpath; #else // Needs to be defined here because those gotos would skip the // initialization of 'cmdline' and 'argv' if it would be defined later. std::ostringstream cmdline; std::list<std::string> argv; #endif if ((!full_init_done) && (log_flags.task)) { msg_printf(wup->project, MSG_INFO, "Starting %s", result->name ); } if (log_flags.cpu_sched) { msg_printf(wup->project, MSG_INFO, "[cpu_sched] Starting %s%s", result->name, (full_init_done) ? " (resume)" : " (initial)" ); } // Always check if all required files are present. If not, trigger // re-downloads and don't start the science application. FILE_INFO_PSET missing_file_infos; retval = gstate.input_files_available(result, true, &missing_file_infos); if (retval) { for (FILE_INFO_PSET::iterator it = missing_file_infos.begin(); it != missing_file_infos.end(); ++it) { FILE_INFO* fip = *it; if (fip) { err_stream << "Input file " << fip->name << " missing or invalid: " << retval; } else { err_stream << "Input file missing or invalid"; // We can't trigger a new download if we don't have // any file information. Just fail here as before. goto error; } fip->status = FILE_NOT_PRESENT; } } if (!missing_file_infos.empty()) { // Some files are missing and are set for re-transfer. // Update status and return without error. result->set_state(RESULT_FILES_DOWNLOADING, "start"); set_task_state(PROCESS_UNINITIALIZED, "start"); next_scheduler_state = PROCESS_UNINITIALIZED; return 0; } if (!full_init_done) { checkpoint_cpu_time = 0; checkpoint_wall_time = gstate.now; } current_cpu_time = checkpoint_cpu_time; episode_start_cpu_time = checkpoint_cpu_time; debt_interval_start_cpu_time = checkpoint_cpu_time; graphics_request_queue.init(result->name); // reset message queues process_control_queue.init(result->name); if (!app_client_shm.shm) { retval = get_shmem_seg_name(); if (retval) { err_stream << "Can't get shared memory segment name: " << boincerror(retval); goto error; } } // this must go AFTER creating shmem name, // since the shmem name is part of the file // retval = write_app_init_file(); if (retval) { err_stream << "Can't write init file: " << retval; goto error; } // set up applications files // strcpy(exec_name, ""); for (i=0; i<app_version->app_files.size(); i++) { fref = app_version->app_files[i]; FILE_INFO* fip = fref.file_info; std::string file_path = get_pathname(fip); if (fref.main_program) { if (is_image_file(fip->name)) { err_stream << "Main program " << fip->name << " is an image file"; retval = ERR_NO_SIGNATURE; goto error; } if (!fip->executable && !wup->project->anonymous_platform) { err_stream << "Main program " << fip->name << " is not executable"; retval = ERR_NO_SIGNATURE; goto error; } safe_strcpy(exec_name, fip->name.c_str()); safe_strcpy(exec_path, file_path.c_str()); } // anonymous platform may use different files than // when the result was started, so link files even if not first time if ((!full_init_done) || (wup->project->anonymous_platform)) { retval = setup_file(result->project, fip, fref, file_path, slot_dir, true); if (retval) { err_stream << "Can't link input file"; goto error; } } } if (!strlen(exec_name)) { err_stream << "No main program specified"; retval = ERR_NOT_FOUND; goto error; } // set up input, output files if (!full_init_done) { for (i=0; i<wup->input_files.size(); i++) { fref = wup->input_files[i]; const FILE_INFO* fip = fref.file_info; std::string file_path = get_pathname(fref.file_info); retval = setup_file(result->project, fip, fref, file_path, slot_dir, true); if (retval) { err_stream << "Can't link input file"; goto error; } } for (i=0; i<result->output_files.size(); i++) { fref = result->output_files[i]; if (fref.copy_file) continue; const FILE_INFO* fip = fref.file_info; std::string file_path = get_pathname(fref.file_info); retval = setup_file(result->project, fip, fref, file_path, slot_dir, false); if (retval) { err_stream << "Can't link output file"; goto error; } } full_init_done = true; } link_user_files(); if (gstate.exit_before_start) { exit(0); } #ifdef _WIN32 PROCESS_INFORMATION process_info; STARTUPINFO startup_info; LPVOID environment_block = NULL; char error_msg[1024]; char error_msg2[1024]; memset(&process_info, 0, sizeof(process_info)); memset(&startup_info, 0, sizeof(startup_info)); startup_info.cb = sizeof(startup_info); // suppress 2-sec rotating hourglass cursor on startup // startup_info.dwFlags = STARTF_FORCEOFFFEEDBACK; app_client_shm.reset_msgs(); if (config.run_apps_manually) { // fill in core client's PID so we won't think app has exited pid = GetCurrentProcessId(); pid_handle = GetCurrentProcess(); set_task_state(PROCESS_EXECUTING, "start"); return 0; } // NOTE: in Windows, stderr is redirected in boinc_init_diagnostics(); cmd_line = exec_path + std::string(" ") + wup->command_line; if (strlen(app_version->cmdline)) { cmd_line += std::string(" ") + app_version->cmdline; } slotdirpath = relative_to_absolute(slot_dir); bool success = false; for (i=0; i<5; i++) { if (sandbox_account_service_token != NULL) { // Find CreateEnvironmentBlock/DestroyEnvironmentBlock pointers tCEB pCEB = NULL; tDEB pDEB = NULL; HMODULE hUserEnvLib = NULL; hUserEnvLib = LoadLibrary("userenv.dll"); if (hUserEnvLib) { pCEB = (tCEB) GetProcAddress(hUserEnvLib, "CreateEnvironmentBlock"); pDEB = (tDEB) GetProcAddress(hUserEnvLib, "DestroyEnvironmentBlock"); } if (!pCEB(&environment_block, sandbox_account_service_token, FALSE)) { if (log_flags.task) { windows_error_string(error_msg, sizeof(error_msg)); msg_printf(wup->project, MSG_INFO, "Process environment block creation failed: %s", error_msg ); } } if (CreateProcessAsUser( sandbox_account_service_token, exec_path, (LPSTR)cmd_line.c_str(), NULL, NULL, FALSE, CREATE_NEW_PROCESS_GROUP|CREATE_NO_WINDOW|IDLE_PRIORITY_CLASS|CREATE_UNICODE_ENVIRONMENT, environment_block, slotdirpath.c_str(), &startup_info, &process_info )) { success = true; break; } else { windows_error_string(error_msg, sizeof(error_msg)); msg_printf(wup->project, MSG_INTERNAL_ERROR, "Process creation failed: %s", error_msg ); } if (!pDEB(environment_block)) { if (log_flags.task) { windows_error_string(error_msg, sizeof(error_msg2)); msg_printf(wup->project, MSG_INFO, "Process environment block cleanup failed: %s", error_msg2 ); } } if (hUserEnvLib) { pCEB = NULL; pDEB = NULL; FreeLibrary(hUserEnvLib); } } else { if (CreateProcess( exec_path, (LPSTR)cmd_line.c_str(), NULL, NULL, FALSE, CREATE_NEW_PROCESS_GROUP|CREATE_NO_WINDOW|IDLE_PRIORITY_CLASS, NULL, slotdirpath.c_str(), &startup_info, &process_info )) { success = true; break; } else { windows_error_string(error_msg, sizeof(error_msg)); msg_printf(wup->project, MSG_INTERNAL_ERROR, "Process creation failed: %s", error_msg ); } } boinc_sleep(drand()); } if (!success) { err_stream << "CreateProcess() failed - " << error_msg; retval = ERR_EXEC; goto error; } pid = process_info.dwProcessId; pid_handle = process_info.hProcess; CloseHandle(process_info.hThread); // thread handle is not used #else // Unix/Linux/Mac case // Set up core/app shared memory seg if needed // if (!app_client_shm.shm) { if (app_version->api_major_version() >= 6) { // Use mmap() shared memory std::string buf = slot_dir + std::string("/") + std::string(MMAPPED_FILE_NAME); if (g_use_sandbox) { if (!boinc_file_exists(buf.c_str())) { int fd = open(buf.c_str(), O_RDWR | O_CREAT, 0660); if (fd >= 0) { close (fd); #ifdef SANDBOX set_to_project_group(buf.c_str()); #endif } } } retval = create_shmem_mmap( buf.c_str(), sizeof(SHARED_MEM), (void**)&app_client_shm.shm ); } else { // Use shmget() shared memory retval = create_shmem( shmem_seg_name, sizeof(SHARED_MEM), gstate.boinc_project_gid, (void**)&app_client_shm.shm ); if (retval) { needs_shmem = true; destroy_shmem(shmem_seg_name); return retval; } } needs_shmem = false; } app_client_shm.reset_msgs(); #if (defined (__APPLE__) && (defined(__i386__) || defined(__x86_64__))) // PowerPC apps emulated on i386 Macs crash if running graphics powerpc_emulated_on_i386 = ! is_native_i386_app(exec_path); #endif if (config.run_apps_manually) { pid = getpid(); // use the client's PID set_task_state(PROCESS_EXECUTING, "start"); return 0; } // Prepare command line for the science app: cmdline << wup->command_line; if (strlen(app_version->cmdline)) { cmdline << ' ' << app_version->cmdline; } argv = parse_command_line(cmdline.str().c_str()); if (log_flags.task_debug) { debug_print_argv(argv); } pid = fork(); if (pid == -1) { err_stream << "fork() failed: " << strerror(errno); retval = ERR_FORK; goto error; } if (pid == 0) { // from here on we're running in a new process. // If an error happens, // exit nonzero so that the core client knows there was a problem. // don't pass stdout to the app // int fd = open("/dev/null", O_RDWR); dup2(fd, STDOUT_FILENO); close(fd); // add to library path: // - the project dir (../../projects/X) // - the slot dir (.) // - the Synecdoche dir (../..) // We use relative paths in case higher-level dirs // are not readable to the account under which app runs // std::string pdir = get_project_dir(wup->project); std::ostringstream libpath; const char* env_lib_path = getenv("LD_LIBRARY_PATH"); if (env_lib_path) { libpath << env_lib_path << ':'; } libpath << "../../" << pdir << ":.:../.."; setenv("LD_LIBRARY_PATH", libpath.str().c_str(), 1); retval = chdir(slot_dir.c_str()); if (retval) { perror("chdir"); fflush(NULL); _exit(errno); } #if 0 // set stack size limit to the max. // Some BOINC apps have reported problems with exceeding // small stack limits (e.g. 8 MB) // and it seems like the best thing to raise it as high as possible // struct rlimit rlim; #define MIN_STACK_LIMIT 64000000 getrlimit(RLIMIT_STACK, &rlim); if (rlim.rlim_cur != RLIM_INFINITY && rlim.rlim_cur <= MIN_STACK_LIMIT) { if (rlim.rlim_max == RLIM_INFINITY || rlim.rlim_max > MIN_STACK_LIMIT) { rlim.rlim_cur = MIN_STACK_LIMIT; } else { rlim.rlim_cur = rlim.rlim_max; } setrlimit(RLIMIT_STACK, &rlim); } #endif // hook up stderr to a specially-named file // freopen(STDERR_FILE, "a", stderr); // set idle process priority #ifdef HAVE_SETPRIORITY if (setpriority(PRIO_PROCESS, 0, PROCESS_IDLE_PRIORITY)) { perror("setpriority"); } #endif std::string path = std::string("../../") + std::string(exec_path); if (g_use_sandbox) { std::ostringstream switcher_path; switcher_path << "../../" << SWITCHER_DIR << '/' << SWITCHER_FILE_NAME; argv.push_front(exec_name); argv.push_front(path); argv.push_front(SWITCHER_FILE_NAME); // Files written by projects have user boinc_project and group boinc_project, // so they must be world-readable so Synecdoche can read them. umask(2); retval = do_execv(switcher_path.str(), argv); } else { argv.push_front(exec_name); retval = do_execv(path, argv); } msg_printf(wup->project, MSG_INTERNAL_ERROR, "Process creation (%s) failed: %s, errno=%d\n", path.c_str(), boincerror(retval), errno ); perror("execv"); fflush(NULL); _exit(errno); } if (log_flags.task_debug) { msg_printf(wup->project, MSG_INFO, "[task_debug] ACTIVE_TASK::start(): forked process: pid %d\n", pid ); } #endif set_task_state(PROCESS_EXECUTING, "start"); return 0; // go here on error; "error_msg" contains error message, "retval" is nonzero // error: // if something failed, it's possible that the executable was munged. // Verify it to trigger another download. // gstate.input_files_available(result, true); gstate.report_result_error(*result, "%s", err_stream.str().c_str()); set_task_state(PROCESS_COULDNT_START, "start"); return retval; }
/// Write the app init file. /// This is done before starting the app, /// and when project prefs have changed during app execution. /// /// \return 0 on success, #ERR_FOPEN if the file could not be opened. /// /// \todo This function was modified to use ofstream instead of boinc_fopen(). /// This means the error checking and retry mechanisms of boinc_fopen() aren't /// used now. We may need to restore them. --NA int ACTIVE_TASK::write_app_init_file() { APP_INIT_DATA aid; memset(&aid, 0, sizeof(aid)); aid.major_version = BOINC_MAJOR_VERSION; aid.minor_version = BOINC_MINOR_VERSION; aid.release = BOINC_RELEASE; aid.app_version = app_version->version_num; safe_strcpy(aid.app_name, wup->app->name); safe_strcpy(aid.symstore, wup->project->symstore); safe_strcpy(aid.acct_mgr_url, gstate.acct_mgr_info.acct_mgr_url); if (wup->project->project_specific_prefs.length()) { aid.project_preferences = strdup(wup->project->project_specific_prefs.c_str()); } aid.hostid = wup->project->hostid; safe_strcpy(aid.user_name, wup->project->user_name); safe_strcpy(aid.team_name, wup->project->team_name); std::string project_path = relative_to_absolute(get_project_dir(wup->project)); strlcpy(aid.project_dir, project_path.c_str(), sizeof(aid.project_dir)); std::string buf = relative_to_absolute(""); strlcpy(aid.boinc_dir, buf.c_str(), sizeof(aid.boinc_dir)); strcpy(aid.authenticator, wup->project->authenticator); aid.slot = slot; strcpy(aid.wu_name, wup->name); aid.user_total_credit = wup->project->user_total_credit; aid.user_expavg_credit = wup->project->user_expavg_credit; aid.host_total_credit = wup->project->host_total_credit; aid.host_expavg_credit = wup->project->host_expavg_credit; double rrs = gstate.runnable_resource_share(); if (rrs) { aid.resource_share_fraction = wup->project->resource_share/rrs; } else { aid.resource_share_fraction = 1; } aid.rsc_fpops_est = wup->rsc_fpops_est; aid.rsc_fpops_bound = wup->rsc_fpops_bound; aid.rsc_memory_bound = wup->rsc_memory_bound; aid.rsc_disk_bound = wup->rsc_disk_bound; aid.computation_deadline = result->computation_deadline(); aid.checkpoint_period = gstate.ncpus * gstate.global_prefs.disk_interval; aid.fraction_done_start = 0; aid.fraction_done_end = 1; #ifdef _WIN32 strcpy(aid.shmem_seg_name, shmem_seg_name); #else aid.shmem_seg_name = shmem_seg_name; #endif // wu_cpu_time is the CPU time at start of session, // not the checkpoint CPU time // At the start of an episode these are equal, but not in the middle! // aid.wu_cpu_time = episode_start_cpu_time; std::string init_data_path = slot_dir + std::string("/") + std::string(INIT_DATA_FILE); std::ofstream f(init_data_path.c_str(), std::ios::out); if (!f.is_open()) { msg_printf(wup->project, MSG_INTERNAL_ERROR, "Failed to open init file %s", init_data_path.c_str() ); return ERR_FOPEN; } aid.host_info = gstate.host_info; aid.global_prefs = gstate.global_prefs; aid.proxy_info = gstate.proxy_info; write_init_data_file(f, aid); return 0; }
/* * Start the dialog that ask to the user where save the video * containing the screencast. * This function take as input the recorder tool button in ardesia bar * return true is the recorder is started. */ gboolean start_save_video_dialog (GtkToolButton *toolbutton, GtkWindow *parent) { gboolean status = FALSE; gchar *filename = g_strdup_printf ("%s", get_project_name ()); GtkWidget *chooser = gtk_file_chooser_dialog_new (gettext ("Save video as ogv"), parent, GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE_AS, GTK_RESPONSE_ACCEPT, NULL); gtk_window_set_modal (GTK_WINDOW (chooser), TRUE); gtk_window_set_keep_above (GTK_WINDOW (chooser), TRUE); gtk_window_set_title (GTK_WINDOW (chooser), gettext ("Choose a file")); gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (chooser), get_project_dir ()); gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (chooser), filename); start_virtual_keyboard (); if (gtk_dialog_run (GTK_DIALOG (chooser)) == GTK_RESPONSE_ACCEPT) { gchar *supported_extension = ".ogv"; gchar *filename_copy = (gchar *) NULL; g_free (filename); filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser)); filename_copy = g_strdup_printf ("%s", filename); if (!g_str_has_suffix (filename, supported_extension)) { g_free (filename_copy); filename_copy = g_strdup_printf ("%s%s", filename, supported_extension); } g_free (filename); filename = filename_copy; if (file_exists (filename)) { gint result = show_override_dialog (GTK_WINDOW (chooser)); if ( result == GTK_RESPONSE_NO) { g_free (filename); filename = NULL; gtk_widget_destroy (chooser); chooser = NULL; return status; } } else { FILE *stream = g_fopen (filename, "w"); if (stream == NULL) { show_could_not_write_dialog (GTK_WINDOW (chooser)); } else { fclose (stream); } } recorder_pid = call_recorder (filename, "start"); status = (recorder_pid > 0); } stop_virtual_keyboard (); if (chooser) { gtk_widget_destroy (chooser); chooser = NULL; } g_free (filename); filename = NULL; return status; }
/* * Start the dialog that ask to the user where save the image * containing the screenshot. */ void start_save_image_dialog (GtkToolButton *toolbutton, GtkWindow *parent) { GtkWidget *preview = NULL; gint preview_width = 128; gint preview_height = 128; GdkPixbuf *preview_pixbuf = NULL; gchar *filename = ""; gchar *filename_copy = ""; gchar *supported_extension = ".pdf"; gint run_status = GTK_RESPONSE_NO; gboolean screenshot = FALSE; GdkPixbuf *buf = grab_screenshot (); GtkWidget *chooser = gtk_file_chooser_dialog_new (gettext ("Export as pdf"), parent, GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE_AS, GTK_RESPONSE_ACCEPT, NULL); gtk_window_set_modal (GTK_WINDOW (chooser), TRUE); gtk_window_set_keep_above (GTK_WINDOW (chooser), TRUE); gtk_window_set_title (GTK_WINDOW (chooser), gettext ("Choose a file")); /* Save the preview in a buffer. */ preview = gtk_image_new (); preview_pixbuf = gdk_pixbuf_scale_simple (buf, preview_width, preview_height, GDK_INTERP_BILINEAR); gtk_image_set_from_pixbuf (GTK_IMAGE (preview), preview_pixbuf); gtk_file_chooser_set_preview_widget (GTK_FILE_CHOOSER (chooser), preview); g_object_unref (preview_pixbuf); preview_pixbuf = NULL; gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (chooser), get_project_dir ()); filename = get_default_filename (); gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (chooser), filename); start_virtual_keyboard (); run_status = gtk_dialog_run (GTK_DIALOG (chooser)); if (run_status == GTK_RESPONSE_ACCEPT) { g_free (filename); filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser)); filename_copy = g_strdup_printf ("%s", filename); screenshot = TRUE; supported_extension = ".png"; if (!g_str_has_suffix (filename, supported_extension)) { g_free (filename_copy); filename_copy = g_strdup_printf ("%s%s", filename, supported_extension); } g_free (filename); filename = filename_copy; if (file_exists (filename)) { gint result = show_override_dialog (GTK_WINDOW (chooser)); if ( result == GTK_RESPONSE_NO) { screenshot = FALSE; } } else { FILE *stream = g_fopen (filename, "w"); if (stream == NULL) { show_could_not_write_dialog (GTK_WINDOW (chooser)); } else { fclose (stream); } } } stop_virtual_keyboard (); gtk_widget_destroy (preview); preview = NULL; if (chooser != NULL) { gtk_widget_destroy (chooser); chooser = NULL; } if (screenshot) { /* Store the buffer on file. */ save_pixbuf_on_png_file (buf, filename); /* Add to the list of the artefacts created in the session. */ add_artifact (filename); } g_free (filename); filename = NULL; g_object_unref (buf); buf = NULL; }