📄 mainwindow.cpp
字号:
standard_size, standard_size); } // processing stops here return true;}void MainWindow::strip(std::string& text) { // erase any trailing space or tab while (!text.empty() && text.find_last_of(" \t") == text.size() - 1) { text.resize(text.size() - 1); } // erase any leading space or tab while (!text.empty() && (text[0] == ' ' || text[0] == '\t')) { text.erase(0, 1); }}MessageText::MessageText(void) { text.set_wrap_mode(Gtk::WRAP_WORD); text.set_editable(false); text.unset_flags(Gtk::CAN_FOCUS); add(text); set_shadow_type(Gtk::SHADOW_IN); set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS); Gdk::Color red; red.set_rgb_p(0.8, 0, 0); Glib::RefPtr<Gdk::Colormap> colourmap_r = Gtk::Widget::get_default_colormap(); colourmap_r->alloc_color(red); red_tag_r = Gtk::TextTag::create(); red_tag_r->property_foreground_gdk() = red; text.get_buffer()->get_tag_table()->add(red_tag_r); // save the current working directory before MainWindow::MainWindow can get // at it, in case it is needed in future by reset_logfile#ifndef PATH_MAX#define PATH_MAX 1023#endif char* path_buffer; int count; void* success; for (count = 1, success = 0; !success && count < 10; count++) { path_buffer = new char[(PATH_MAX * count) + 1]; success = getcwd(path_buffer, PATH_MAX * count); if (success) { starting_dirname = path_buffer; starting_dirname += '/'; } delete[] path_buffer; } // now open the log file if required if (!prog_config.logfile_name.empty()) { try { std::string temp(Glib::filename_from_utf8(prog_config.logfile_name)); if (temp[0] != '/') temp.insert(0, starting_dirname); // provide an absolute path name logfile.open(temp.c_str(), std::ios::app | std::ios::out); if (!logfile) { { // lock the Prog_config object while we modify it Glib::Mutex::Lock lock(*prog_config.mutex_p); prog_config.logfile_name = ""; } std::string message("Can't open logfile "); message += temp; message += '\n'; write_red_slot(message.c_str()); } else { struct std::tm* time_p; std::time_t time_count; std::time(&time_count); time_p = std::localtime(&time_count); const char date_description_format[] = "%H%M %Z %d %b %Y"; const int max_description_datesize = 126; char date_description[max_description_datesize]; std::strftime(date_description, max_description_datesize, date_description_format, time_p); logfile << "\n\n***********************\n" "Beginning fax log at " << date_description << '\n' << std::endl; // set a timeout to flush every one minute timer_slot_connection = Glib::signal_timeout().connect(sigc::mem_fun(*this, &MessageText::flush_logfile_timer_slot), LOGFILE_TIMER_INTERVAL); } // save the logfile name in the local version of logfile_name // in case reset_logfile() is called later so we can test whether it has changed logfile_name = Glib::filename_from_utf8(prog_config.logfile_name); } catch (Glib::ConvertError&) { write_error("UTF-8 conversion error in MessageText::MessageText()\n"); beep(); } }}MessageText::~MessageText(void) { struct std::tm* time_p; std::time_t time_count; std::time(&time_count); time_p = std::localtime(&time_count); const char date_description_format[] = "%H%M %Z %d %b %Y"; const int max_description_datesize = 126; char date_description[max_description_datesize]; std::strftime(date_description, max_description_datesize, date_description_format, time_p); logfile << "\n\nEnding fax log at " << date_description << '\n' << "***********************\n" << std::endl; logfile.clear(); logfile.close();}void MessageText::reset_logfile(void) { // check pre-conditions try { if (logfile_name == Glib::filename_from_utf8(prog_config.logfile_name)) return; // no change! } catch (Glib::ConvertError&) { write_error("UTF-8 conversion error in MessageText::reset_logfile()\n"); beep(); return; } // proceed // first close the log file if required if (!logfile_name.empty()) { struct std::tm* time_p; std::time_t time_count; std::time(&time_count); time_p = std::localtime(&time_count); const char date_description_format[] = "%H%M %Z %d %b %Y"; const int max_description_datesize = 126; char date_description[max_description_datesize]; std::strftime(date_description, max_description_datesize, date_description_format, time_p); logfile << "\n\nEnding fax log at " << date_description << '\n' << "***********************\n" << std::endl; logfile.clear(); logfile.close(); // and now disconnect the old timer connection timer_slot_connection.disconnect(); } // now open the new log file if required if (!prog_config.logfile_name.empty()) { // we do not need to check the conversion here - if prog_config.logfile_name // is not valid UTF-8, then it would have already thrown above std::string temp(Glib::filename_from_utf8(prog_config.logfile_name)); if (temp[0] != '/') temp.insert(0, starting_dirname); // provide an absolute path name logfile.open(temp.c_str(), std::ios::app | std::ios::out); if (!logfile) { { // lock the Prog_config object while we modify it Glib::Mutex::Lock lock(*prog_config.mutex_p); prog_config.logfile_name = ""; } std::string message("Can't open logfile "); message += temp; message += '\n'; write_red_slot(message.c_str()); } else { struct std::tm* time_p; std::time_t time_count; std::time(&time_count); time_p = std::localtime(&time_count); const char date_description_format[] = "%H%M %Z %d %b %Y"; const int max_description_datesize = 126; char date_description[max_description_datesize]; std::strftime(date_description, max_description_datesize, date_description_format, time_p); logfile << "\n\n***********************\n" "Beginning fax log at " << date_description << '\n' << std::endl; // set a timeout to flush every one minute timer_slot_connection = Glib::signal_timeout().connect(sigc::mem_fun(*this, &MessageText::flush_logfile_timer_slot), LOGFILE_TIMER_INTERVAL); } } // save the logfile name in the local version of logfile_name // in case reset_logfile() is called again later // we don't need to check the conversion here, as if it was invalid it // would have thrown above logfile_name = Glib::filename_from_utf8(prog_config.logfile_name);}void MessageText::cleanify(std::string& message) { std::string::size_type chunk_start = 0; std::string::size_type chunk_end; while (chunk_start != std::string::npos) { std::string::size_type chunk_size; chunk_end = message.find('\n', chunk_start); // include in the search chunk any '\n' found if (chunk_end + 1 >= message.size()) chunk_end = std::string::npos; else if (chunk_end != std::string::npos) chunk_end++; // now search the relevant string/substring and erase from message if (chunk_end == std::string::npos) chunk_size = message.size() - chunk_start; else chunk_size = chunk_end - chunk_start; if (message.substr(chunk_start, chunk_size).find(" Copyright ") != std::string::npos || message.substr(chunk_start, chunk_size).find(" compiled ") != std::string::npos || message.substr(chunk_start, chunk_size).find("Error: terminating on signal 15") != std::string::npos) { message.erase(chunk_start, chunk_size); // if we have erased this chunk then we don't want to reset chunk_start // unless we have finished examining message if (chunk_end == std::string::npos) chunk_start = std::string::npos; } // if we didn't erase the last chunk, then we need to reset // chunk_start to beginning of next substring (or to string::npos) else chunk_start = chunk_end; }}void MessageText::write_black_slot(const char* message) { std::string temp(message); cleanify(temp); bool scrolling = false; if (get_vadjustment()->get_value() >= (get_vadjustment()->get_upper() - get_vadjustment()->get_page_size() - 1e-12)) { scrolling = true; } Glib::RefPtr<Gtk::TextBuffer> buffer_r = text.get_buffer(); buffer_r->insert(buffer_r->end(), temp); if (scrolling) text.scroll_to_mark(buffer_r->create_mark("end", buffer_r->end()), 0.0); // now relay to standard output write(1, temp.c_str(), temp.size()); // now log to file if required if (!prog_config.logfile_name.empty()) logfile << temp;}void MessageText::write_red_slot(const char* message) { std::string temp(message); cleanify(temp); bool scrolling = false; if (get_vadjustment()->get_value() >= (get_vadjustment()->get_upper() - get_vadjustment()->get_page_size() - 1e-12)) { scrolling = true; } Glib::RefPtr<Gtk::TextBuffer> buffer_r = text.get_buffer(); buffer_r->insert_with_tag(buffer_r->end(), temp, red_tag_r); if (scrolling) text.scroll_to_mark(buffer_r->create_mark("end", buffer_r->end()), 0.0); // now relay to standard error write(2, temp.c_str(), temp.size()); // now log to file if required if (!prog_config.logfile_name.empty()) logfile << temp;}bool MessageText::flush_logfile_timer_slot(void) { logfile.flush(); return true; // we want a multi-shot timer}StatusLine::StatusLine(const int standard_size): Gtk::HBox(false, 0), status_label(gettext("Inactive")), help_label(gettext("Press F1 for help")) { set_border_width(2); status_label.set_size_request(standard_size * 7, standard_size - 4); status_frame.set_shadow_type(Gtk::SHADOW_IN); status_frame.add(status_label); pack_start(status_frame, true, true, 0); help_label.set_size_request(standard_size * 6, standard_size - 4); help_frame.set_shadow_type(Gtk::SHADOW_IN); help_frame.add(help_label); pack_end(help_frame, true, true, 0); show_all();}void StatusLine::set_colour(const Glib::RefPtr<Gtk::Style>& current_style_r) { // make the status label display in red // Note: we need to take a copy of the existing style, as the existing // style is shared by all the program's widgets. If we operate // directly on the Gtk::Style object returned (by Glib::RefPtr) by // Gtk::Widget::get_style(), say with Gtk::Style::set_fg(), // we will alter it for everything! Glib::RefPtr<Gtk::Style> new_style_r(current_style_r->copy()); Gdk::Color red; red.set_rgb_p(0.9, 0, 0); Glib::RefPtr<Gdk::Colormap> colourmap_r = Gtk::Widget::get_default_colormap(); colourmap_r->alloc_color(red); new_style_r->set_fg(Gtk::STATE_NORMAL, red); status_label.set_style(new_style_r);}int connect_to_stderr(void) { int result = MainWindow::error_pipe.connect_to_stderr(); if (!result) MainWindow::connected_to_stderr = true; return result;} ssize_t write_error(const char* message) { // this writes to a pipe (which will provide asynchronous to synchronous conversion) // so it can be used by different threads without upsetting GTK+. It also only // uses async-signal-safe system functions and is thread safe because (a) although // Pipe_fifo::read() and Pipe_fifo::write() check the value of Pipe_fifo::read_fd and // Pipe_fifo::write_fd respectively, and Pipe_fifo::open(), Pipe_fifo::make_writeonly(), // Pipe_fifo::make_readonly(), Pipe_fifo::close(), Pipe_fifo::connect_to_stdin(), // Pipe_fifo::connect_to_stdout() and Pipe_fifo::connect_to_stderr() change those // values, all but the last one are never called on MainWindow::error_pipe until // (if at all) error_pipe goes out of scope when global objects are destroyed // as the program exits, and Pipe_fifo::connect_to_stderr() is only ever called // after fork()ing into a new single-threaded process if (!MainWindow::connected_to_stderr) return MainWindow::error_pipe.write(message); else return ::write(2, message, std::strlen(message));}void close_signalhandler(int) { close_flag = true;}void childexit_signalhandler(int) { int stat_val; pid_t result; while ((result = waitpid(-1, &stat_val, WNOHANG)) > 0) { int exit_code = -1; if (WIFEXITED(stat_val)) exit_code = WEXITSTATUS(stat_val); //if (!efax_controller_childexit_handler(result, exit_code)) // for debugging //std::cout << "Not efax_controller child" << std::endl; //std::cout << "Child pid is " << result << std::endl; //std::cout << "Child exit code is " << exit_code << std::endl; efax_controller_childexit_handler(result, exit_code); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -