📄 fax_list.cpp
字号:
// is going on pid_t pid = fork(); if (pid == -1) { write_error("Fork error - exiting\n"); std::exit(FORK_ERROR); } if (!pid) { // child print process // make the call to connect_to_stderr() in this child process // dependent on calling a print confirmation popup dialog: if we have // elected not to bring up such a dialog, we are probably using a // print manager such as kprinter, and we can get confusing messages // from stderr from these // no mutex is required for the access to prog_config.print_popup // because we have fork()ed into a separate process if (prog_config.print_popup) connect_to_stderr(); // now create a blocking pipe which the print processes can use to // communicate via stdout/stdin Pipe_fifo fork_pipe(Pipe_fifo::block); pid_t pid = fork(); if (pid == -1) { write_error("Fork error - exiting\n"); _exit(FORK_ERROR); } if (!pid) { // process to exec to print_from_stdin() fork_pipe.connect_to_stdin(); execvp(print_from_stdin_parms.first, print_from_stdin_parms.second); // if we reached this point, then the execvp() call must have failed // write error and then end process - use _exit(), not exit() write_error("Can't find the print program - please check your installation\n" "and the PATH environmental variable\n"); _exit(0); } // this is the process which will send postscript to stdout fork_pipe.connect_to_stdout(); execvp(fax_to_ps_parms.first, fax_to_ps_parms.second); // if we reached this point, then the execvp() call must have failed // report error and then end process - use _exit(), not exit() write_error("Can't find the efix-0.9a program - please check your installation\n" "and the PATH environmental variable\n"); _exit(0); } // release the memory allocated on the heap for // the redundant print_from_stdin_parms and fax_to_ps_parms // we are in the main parent process here - no worries about // only being able to use async-signal-safe functions delete_parms(print_from_stdin_parms); } delete_parms(fax_to_ps_parms);}void FaxListDialog::view_fax(void) { // we do not need a mutex before reading prog_config.ps_view_cmd // as although read in FaxListDialog::get_ps_viewer_parms(), // the thread which executes that method is launched below as // FaxListsDialog::view_fax_thread() and is therefore not running // at this stage if (fax_list_manager.is_fax_selected() && !prog_config.ps_view_cmd.empty()) { // fax_basename_sem is initialised to a count of 1, so this will stop // fax_basename being overwritten until Sem_sync::post() is called in // print_fax_thread() or view_fax_thread() or on Glib::ThreadError being // caught fax_basename_sem.wait(); fax_basename = prog_config.working_dir; if (mode == FaxListEnum::received) fax_basename += "/faxin/"; else fax_basename += "/faxsent/"; // we don't need to use a Glib conversion function here - we know the // fax name is just plain ASCII numbers std::string fax_number(fax_list_manager.get_fax_number()); fax_basename += fax_number; fax_basename += '/'; fax_basename += fax_number; fax_basename += '.'; // now block off the signals for which we have set handlers so that the socket server // thread does not receive the signals, otherwise we will have memory synchronisation // issues in multi-processor systems - we will unblock in the initial (GUI) thread // as soon as the socket server thread has been launched sigset_t sig_mask; sigemptyset(&sig_mask); sigaddset(&sig_mask, SIGCHLD); sigaddset(&sig_mask, SIGQUIT); sigaddset(&sig_mask, SIGTERM); sigaddset(&sig_mask, SIGINT); sigaddset(&sig_mask, SIGHUP);#ifdef HAVE_PTHREAD_SIGMASK pthread_sigmask(SIG_BLOCK, &sig_mask, 0);#else sigprocmask(SIG_BLOCK, &sig_mask, 0);#endif try { Glib::Thread::create(sigc::mem_fun(*this, &FaxListDialog::view_fax_thread), false); } catch (Glib::ThreadError&) { write_error("Cannot start new view fax thread, fax cannot be viewed\n"); fax_basename_sem.post(); } // now unblock the signals so that the initial (GUI) thread can receive them#ifdef HAVE_PTHREAD_SIGMASK pthread_sigmask(SIG_UNBLOCK, &sig_mask, 0);#else sigprocmask(SIG_UNBLOCK, &sig_mask, 0);#endif }}void FaxListDialog::view_fax_thread(void) { // get a temporary file char filename[] = "/tmp/efax-gtk-view.XXXXXX"; int file_fd = mkstemp(filename); if (file_fd == -1) { write_error("Failed to make temporary file:\n" "please check permissions in /tmp directory"); _exit(0); } // now create a pipe and proceed to fork to write the postscript to temporary file Pipe_fifo fork_pipe(Pipe_fifo::block); // get the arguments for the exec() call to convert the fax files to // PS format following the next fork() call (because this is a multi- // threaded program, we must do this before fork()ing because we use // functions to get the arguments which are not async-signal-safe) std::pair<const char*, char* const*> fax_to_ps_parms(get_fax_to_ps_parms(fax_basename, false)); // release main GUI thread in print_fax() or view_fax() // waiting for this use of fax_basename to finish fax_basename_sem.post(); // now fork to create the process which will write postscript to stdout pid_t pid = fork(); if (pid == -1) { write_error("Fork error - exiting\n"); _exit(FORK_ERROR); } if (!pid) { // child process which will send postscript to stdout // this is the child process to write to stdin // now we have fork()ed we can connect to stderr connect_to_stderr(); fork_pipe.connect_to_stdout(); execvp(fax_to_ps_parms.first, fax_to_ps_parms.second); // if we reached this point, then the execvp() call must have failed // report error and then end process - use _exit(), not exit() write_error("Can't find the efix-0.9a program - please check your installation\n" "and the PATH environmental variable\n"); _exit(0); } // this is the parent process, which will convert the fax to Postscript // and then pipe it on stdout to write_from_stdin() // first, release the memory allocated on the heap for // the redundant fax_to_ps_parms // we are in the main parent process here - no worries about // only being able to use async-signal-safe functions delete_parms(fax_to_ps_parms); // now write stdin in (containing the generated PS text) to file fork_pipe.connect_to_stdin(); write_from_stdin(file_fd); // the temporary file to be viewed has now been created // so launch a new process to control the viewing process // we will reset handlers and then fork() again having done // so, so that we can wait on the child of child // first get the arguments for the exec() call to launch the fax // viewer following the next fork() call (because this is a multi- // threaded program, we must do this before fork()ing because we use // functions to get the arguments which are not async-signal-safe) std::pair<const char*, char* const*> ps_viewer_parms(get_ps_viewer_parms(filename)); if (ps_viewer_parms.first) { // this will be 0 if get_ps_viewer_parms() // threw a Glib::ConvertError) pid = fork(); if (pid == -1) { write_error("Fork error\n"); std::exit(FORK_ERROR); } if (!pid) { // child view-control process // restore the default SIGCHLD signal handler with SA_RESTART // for systems (such as Linux) which require it. Also unblock // signals in case we are blocking them on launching a thread // elsewhere in this program (I cannot work out from IEEE 1003.1 // whether all masks are emptied on a fork() in any event) sigset_t sig_mask; sigemptyset(&sig_mask); sigaddset(&sig_mask, SIGCHLD); sigaddset(&sig_mask, SIGQUIT); sigaddset(&sig_mask, SIGTERM); sigaddset(&sig_mask, SIGINT); sigaddset(&sig_mask, SIGHUP); // this child process is single threaded, so we can use sigprocmask() // rather than pthread_sigmask() (and should do so as sigprocmask() // is guaranteed to be async-signal-safe) sigprocmask(SIG_UNBLOCK, &sig_mask, 0); struct sigaction sig_act; sig_act.sa_handler = SIG_DFL; sigemptyset(&sig_act.sa_mask);#ifdef SA_RESTART sig_act.sa_flags = SA_RESTART;#else sig_act.sa_flags = 0;#endif sigaction(SIGCHLD, &sig_act, 0); connect_to_stderr(); // now fork() again pid_t pid = fork(); if (pid == -1) { write_error("Fork error - exiting\n"); _exit(FORK_ERROR); } if (!pid) { // child process to call ps_viewer() from execvp(ps_viewer_parms.first, ps_viewer_parms.second); // if we reached this point, then the execvp() call must have failed // report error and then end process - use _exit(), not exit() write_error("Can't find the ps viewer program - please check your installation\n" "and the PATH environmental variable\n"); _exit(0); } // now we are back to the main viewing process again // delete the temporary file // first wait till the ps_viewer() process is closed by the user exiting // the postscript viewing program wait(0); unlink(filename); // now terminate the process _exit(0); } // release the memory allocated on the heap for // the redundant ps_viewer_parms // we are in the main parent process here - no worries about // only being able to use async-signal-safe functions delete_parms(ps_viewer_parms); }}void FaxListDialog::delete_parms(std::pair<const char*, char* const*> parms_pair) { delete[] parms_pair.first; char* const* temp_pp = parms_pair.second; for(; *temp_pp != 0; ++temp_pp) { delete[] *temp_pp; } delete[] parms_pair.second;}void FaxListDialog::refresh_slot(void) { fax_list_manager.refresh(); set_buttons_slot();}EntryDialog::EntryDialog(const int standard_size, const Glib::ustring& entry_text, const Glib::ustring& label_text, Gtk::Window& window): Gtk::Window(Gtk::WINDOW_TOPLEVEL), in_exec_loop(false), ok_button(Gtk::Stock::OK), cancel_button(Gtk::Stock::CANCEL), button_box(Gtk::BUTTONBOX_END, standard_size/2), label(label_text), table(3, 1, false), parent(window) { button_box.add(cancel_button); button_box.add(ok_button); table.attach(label, 0, 1, 0, 1, Gtk::FILL | Gtk::EXPAND, Gtk::FILL | Gtk::EXPAND, standard_size/2, standard_size/4); table.attach(entry, 0, 1, 1, 2, Gtk::FILL | Gtk::EXPAND, Gtk::EXPAND, standard_size/2, standard_size/4); table.attach(button_box, 0, 1, 2, 3, Gtk::FILL | Gtk::EXPAND, Gtk::SHRINK, standard_size/2, standard_size/4); ok_button.signal_clicked().connect(sigc::bind(sigc::mem_fun(*this, &EntryDialog::selected), true)); cancel_button.signal_clicked().connect(sigc::bind(sigc::mem_fun(*this, &EntryDialog::selected), false)); ok_button.set_flags(Gtk::CAN_DEFAULT); cancel_button.set_flags(Gtk::CAN_DEFAULT); add(table); entry.set_text(entry_text); set_title(gettext("Fax description")); set_transient_for(parent); set_type_hint(Gdk::WINDOW_TYPE_HINT_DIALOG); parent.set_sensitive(false); set_modal(true); entry.set_size_request(standard_size * 9, standard_size); set_border_width(standard_size/2); entry.grab_focus(); set_position(Gtk::WIN_POS_CENTER_ON_PARENT); set_resizable(false); set_icon(prog_config.window_icon_r); show_all(); // we now need to deselect what is in the entry entry.select_region(0,0);}void EntryDialog::exec(void) { in_exec_loop = true; Gtk::Main::run();}void EntryDialog::selected(bool accept) { parent.set_sensitive(true); // do this before we emit accepted() hide_all(); if (accept) accepted(entry.get_text()); if (in_exec_loop) Gtk::Main::quit(); // if we have not called exec(), then this dialog is self-owning and it is safe to call `delete this' else delete this;}bool EntryDialog::on_delete_event(GdkEventAny*) { selected(false); return true; // returning true prevents destroy sig being emitted}bool EntryDialog::on_key_press_event(GdkEventKey* event_p) { if (event_p->keyval == GDK_Escape) selected(false); else if (event_p->keyval == GDK_Return && !cancel_button.has_focus()) selected(true); else Gtk::Window::on_key_press_event(event_p); return true; // processing ends here}DescriptionDialog::DescriptionDialog(const int standard_size, const Glib::ustring& text, Gtk::Window& window): EntryDialog(standard_size, text, gettext("Fax description?"), window) {}AddFolderDialog::AddFolderDialog(const int standard_size, Gtk::Window& window): EntryDialog(standard_size, "", gettext("Folder name?\n" "(Note this will be placed in the top\n" "level and can be drag-and-dropped\n" "into other folders)"), window) {}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -