📄 mainwindow.cpp
字号:
is received via the socket and also by Socket_server::remove_file() - Socket_server::remove_file() is called by MainWindow::remove_from_socket_server_filelist() - MainWindow::remove_from_socket_server_filelist() is connected to the EfaxController::remove_from_socket_server_filelist signal and to SocketList::remove_from_socket_server_filelist() - the EfaxController::remove_from_socket_server_filelist signal is emitted by EfaxController::timer_event() when a fax derived from the socket list is successfully sent - the Socket_server::remove_from_socket_server_filelist signal is emitted by SocketServer::remove_file() - Socket_server::remove_file() is connected to the PromptDialog::accepted signal (emitted when a user elects to delete a queued fax from the list of files received for faxing from the socket)*/ Glib::RefPtr<Gdk::Window> window_r = drawing_area.get_window(); if (!socket_server.get_filenames().first->empty()) { Gdk::Color red; red.set_rgb_p(0.7, 0, 0); Glib::RefPtr<Gdk::Colormap> colourmap_r = Gtk::Widget::get_default_colormap(); colourmap_r->alloc_color(red); Glib::RefPtr<Gdk::GC> red_graphics_context_r = Gdk::GC::create(window_r); red_graphics_context_r->set_foreground(red); Glib::RefPtr<Gdk::GC> white_graphics_context_r = drawing_area.get_style()->get_white_gc(); window_r->draw_arc(white_graphics_context_r, true, 6, 6, standard_size - 12, standard_size - 12, 0, 64 * 360); window_r->draw_arc(red_graphics_context_r, true, 8, 8, standard_size - 16, standard_size - 16, 0, 64 * 360); } else { Glib::RefPtr<Gdk::GC> background_graphics_context_r = drawing_area.get_style()->get_bg_gc(drawing_area.get_state()); window_r->draw_rectangle(background_graphics_context_r, true, 0, 0, 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.close(); logfile.clear();}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.close(); logfile.clear(); // 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 with only a mutex in this // function 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 Glib::Mutex::Lock lock(*write_error_mutex_p); 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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -