📄 mainwindow.cpp
字号:
/* Copyright (C) 2001 to 2004 Chris VineThis program is distributed under the General Public Licence, version 2.For particulars of this and relevant disclaimers see the fileCOPYING distributed with the source files.*/#include <sys/types.h>#include <unistd.h>#include <signal.h>#include <sys/stat.h>#include <ctime>#include <cstdlib>#include <cstring>#include <gtkmm/menu.h>#include <gtkmm/style.h>#include <gtkmm/main.h>#include <gtkmm/stock.h>#include <gtkmm/image.h>#include <gdkmm/pixbuf.h>#include <gdkmm/color.h>#include <gdkmm/colormap.h>#include <gdkmm/gc.h>#include <glibmm/main.h>#include <glibmm/convert.h>#include "mainwindow.h"#include "dialogs.h"#include "addressbook.h"#include "file_list.h"#include "settings.h"#include "socket_notify.h"#include "menu_icons.h"#if GTKMM_VERSION >= 24#include <gtk/gtkicontheme.h>#include <gtkmm/icontheme.h>#include "gtk_icon_info_handle.h"#endif#ifdef ENABLE_NLS#include <libintl.h>#endif#define TIMER_INTERVAL 200 // number of milliseconds between timer events for the main timer#define LOGFILE_TIMER_INTERVAL 60000 // number of milliseconds between flushing of logfileextern "C" void close_signalhandler(int);static volatile sig_atomic_t close_flag = false;Pipe_fifo MainWindow::error_pipe(Pipe_fifo::non_block);bool MainWindow::connected_to_stderr = false;static Glib::Mutex* write_error_mutex_p;MainWindow::MainWindow(const std::string& messages,bool start_hidden, bool start_in_standby, const char* filename): // start_hidden and start_in_standby have a default value of // false and filename has a default value of 0 Gtk::Window(Gtk::WINDOW_TOPLEVEL), standard_size(24), obscured(false), minimised(false), file_entry_table(3, 3, false), win_table(5, 3, false), file_entry_frame(gettext("Fax to send")), file_button(gettext("File ")), socket_button(gettext("Socket")), fax_method_label(gettext("Fax entry method: ")), single_file_button(gettext("Single file")), multiple_file_button(gettext("Multiple files")), socket_list_button(gettext("Socket list")), number_button(gettext("Tel number: ")), send_button(gettext("Send fax")), receive_answer_button(gettext("Answer call")), receive_takeover_button(gettext("Take over call")), receive_standby_button(gettext("Standby")), stop_button(gettext("Stop")), status_line(standard_size), tray_item(*this) { // catch any relevant Unix signals for an orderly closedown // catch SIGQUIT, SIGTERM SIGINT SIGHUP // it is safe to use signal() for these signal(SIGQUIT, close_signalhandler); signal(SIGTERM, close_signalhandler); signal(SIGINT, close_signalhandler); signal(SIGHUP, close_signalhandler); // ignore SIGPIPE struct sigaction sig_act_pipe; sig_act_pipe.sa_handler = SIG_IGN; // we don't need to mask off any signals sigemptyset(&sig_act_pipe.sa_mask); sig_act_pipe.sa_flags = 0; sigaction(SIGPIPE, &sig_act_pipe, 0); // if available, set the default standard SIGCHLD signal handler // to restart system functions struct sigaction sig_act_chld; sig_act_chld.sa_handler = SIG_DFL; // we don't need to mask off any signals sigemptyset(&sig_act_chld.sa_mask);#ifdef SA_RESTART sig_act_chld.sa_flags = SA_NOCLDSTOP | SA_RESTART;#else sig_act_chld.sa_flags = SA_NOCLDSTOP;#endif sigaction(SIGCHLD, &sig_act_chld, 0); write_error_mutex_p = new Glib::Mutex; get_longest_button_text(); Gtk::RadioButton::Group class_group(file_button.get_group()); socket_button.set_group(class_group); file_button.set_active(true); fax_method_radio_box.pack_start(file_button, false, false, 0); fax_method_radio_box.pack_start(socket_button, false, false, 0); fax_method_radio_frame.add(fax_method_radio_box); fax_method_box.pack_start(fax_method_label, false, false, 0); fax_method_box.pack_start(fax_method_radio_frame, false, false, 0); fax_method_box.pack_start(fax_method_filler, true, false, 0); fax_method_box.pack_start(drawing_area, false, false, 0); file_entry_table.attach(file_entry, 0, 3, 0, 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, standard_size/3, standard_size/3); file_entry_table.attach(fax_method_box, 0, 3, 1, 2, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, standard_size/3, standard_size/3); file_entry_table.attach(single_file_button, 0, 1, 2, 3, Gtk::EXPAND, Gtk::SHRINK, standard_size/3, standard_size/3); file_entry_table.attach(multiple_file_button, 1, 2, 2, 3, Gtk::EXPAND, Gtk::SHRINK, standard_size/3, standard_size/3); file_entry_table.attach(socket_list_button, 2, 3, 2, 3, Gtk::EXPAND, Gtk::SHRINK, standard_size/3, standard_size/3); file_entry_frame.add(file_entry_table); number_box.pack_start(number_button, false, false, standard_size/2); number_box.pack_start(number_entry, true, true, 0); win_table.attach(file_entry_frame, 0, 3, 0, 1, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, standard_size/3, standard_size/3); win_table.attach(number_box, 0, 3, 1, 2, Gtk::EXPAND | Gtk::FILL, Gtk::SHRINK, standard_size/3, standard_size/3); win_table.attach(text_window, 0, 3, 2, 3, Gtk::EXPAND | Gtk::FILL, Gtk::EXPAND | Gtk::FILL, standard_size/3, standard_size/3); win_table.attach(send_button, 0, 1, 3, 4, Gtk::EXPAND, Gtk::SHRINK, standard_size/3, standard_size/3); win_table.attach(receive_answer_button, 1, 2, 3, 4, Gtk::EXPAND, Gtk::SHRINK, standard_size/3, standard_size/3); win_table.attach(receive_takeover_button, 2, 3, 3, 4, Gtk::EXPAND, Gtk::SHRINK, standard_size/3, standard_size/3); win_table.attach(receive_standby_button, 0, 1, 4, 5, Gtk::EXPAND, Gtk::SHRINK, standard_size/3, standard_size/3); win_table.attach(stop_button, 2, 3, 4, 5, Gtk::EXPAND, Gtk::SHRINK, standard_size/3, standard_size/3); file_button.signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::set_file_items_sensitive_slot)); socket_button.signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::set_socket_items_sensitive_slot)); single_file_button.signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::get_file_slot)); multiple_file_button.signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::file_list_slot)); socket_list_button.signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::socket_list_slot)); number_button.signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::addressbook_slot)); send_button.signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::sendfax_slot)); receive_answer_button.signal_clicked().connect(sigc::bind(sigc::mem_fun(*this, &MainWindow::receive_slot), static_cast<int>(EfaxController::receive_answer))); receive_takeover_button.signal_clicked().connect(sigc::bind(sigc::mem_fun(*this, &MainWindow::receive_slot), static_cast<int>(EfaxController::receive_takeover))); receive_standby_button.signal_clicked().connect(sigc::bind(sigc::mem_fun(*this, &MainWindow::receive_slot), static_cast<int>(EfaxController::receive_standby))); stop_button.signal_clicked().connect(sigc::mem_fun(efax_controller, &EfaxController::stop_slot)); single_file_button.set_flags(Gtk::CAN_DEFAULT); multiple_file_button.set_flags(Gtk::CAN_DEFAULT); socket_list_button.set_flags(Gtk::CAN_DEFAULT); number_button.set_flags(Gtk::CAN_DEFAULT); send_button.set_flags(Gtk::CAN_DEFAULT); receive_answer_button.set_flags(Gtk::CAN_DEFAULT); receive_takeover_button.set_flags(Gtk::CAN_DEFAULT); receive_standby_button.set_flags(Gtk::CAN_DEFAULT); stop_button.set_flags(Gtk::CAN_DEFAULT); // set up the menu bar { // first get the about icon bool have_about_icon = false; Glib::RefPtr<Gdk::Pixbuf> about_pixbuf_r;#if GTKMM_VERSION >= 24 Glib::RefPtr<Gtk::IconTheme> icon_theme_r = Gtk::IconTheme::get_default(); // use the C function to look-up the icon - the gtkmm wrapper does not // check whether look-up succeeded. In addition, Gtk::IconInfo::get_filename() // incorrectly returns a Glib::ustring object instead of a std::string object, // without converting its contents to a valid UTF-8 encoded string Gtk_icon_info_scoped_handle icon_info_h( gtk_icon_theme_lookup_icon(icon_theme_r->gobj(), "stock_about", 16, GtkIconLookupFlags(0))); if (icon_info_h.get()) { // we could use Glib::convert_const_gchar_ptr_to_stdstring, but this is not // part of the publicly documented interface const char* icon_path_p = (const char*)gtk_icon_info_get_filename(icon_info_h.get()); if (icon_path_p) { try { about_pixbuf_r = Gdk::Pixbuf::create_from_file(std::string(icon_path_p)); have_about_icon = true; } catch (Gdk::PixbufError&) { write_error("Pixbuf error in MainWindow::MainWindow()\n"); } } }#endif if (!have_about_icon) { about_pixbuf_r = Gdk::Pixbuf::create_from_xpm_data(about_xpm); } Gtk::Image* image_p; using namespace Gtk::Menu_Helpers; // Create the file menu Gtk::Menu* file_menu_p = manage(new Gtk::Menu); // now fill the file menu MenuList& file_list = file_menu_p->items(); image_p = manage(new Gtk::Image(Gtk::Stock::INDEX, Gtk::ICON_SIZE_MENU)); file_list.push_back(ImageMenuElem(gettext("List _received faxes"), *image_p, sigc::bind(sigc::mem_fun(*this, &MainWindow::fax_list_slot), FaxListEnum::received))); image_p = manage(new Gtk::Image(Gtk::Stock::INDEX, Gtk::ICON_SIZE_MENU)); file_list.push_back(ImageMenuElem(gettext("_List sent faxes"), *image_p, sigc::bind(sigc::mem_fun(*this, &MainWindow::fax_list_slot), FaxListEnum::sent))); file_list.push_back(SeparatorElem()); file_list.push_back(MenuElem(gettext("Queued _faxes from socket"), sigc::mem_fun(*this, &MainWindow::socket_list_slot))); // save this menu item for future use socket_list_item_p = &file_list.back(); image_p = manage(new Gtk::Image(Gtk::Stock::OPEN, Gtk::ICON_SIZE_MENU)); file_list.push_back(ImageMenuElem(gettext("_Enter single file"), *image_p, sigc::mem_fun(*this, &MainWindow::get_file_slot))); // save this menu item for future use single_file_item_p = &file_list.back(); image_p = manage(new Gtk::Image(Gtk::Stock::OPEN, Gtk::ICON_SIZE_MENU)); file_list.push_back(ImageMenuElem(gettext("Enter _multiple files"), *image_p, sigc::mem_fun(*this, &MainWindow::file_list_slot))); // save this menu item for future use multiple_file_item_p = &file_list.back(); file_list.push_back(SeparatorElem()); file_list.push_back(MenuElem(gettext("_Address book"), sigc::mem_fun(*this, &MainWindow::addressbook_slot))); file_list.push_back(SeparatorElem()); image_p = manage(new Gtk::Image(Gtk::Stock::PREFERENCES, Gtk::ICON_SIZE_MENU)); file_list.push_back(ImageMenuElem(gettext("_Settings"), *image_p, sigc::mem_fun(*this, &MainWindow::settings_slot))); file_list.push_back(SeparatorElem()); image_p = manage(new Gtk::Image(Gtk::Stock::QUIT, Gtk::ICON_SIZE_MENU)); file_list.push_back(ImageMenuElem(gettext("_Quit"), *image_p, sigc::mem_fun(*this, &MainWindow::close_slot))); // Create the help menu Gtk::Menu* help_menu_p = manage(new Gtk::Menu); // now fill the help menu MenuList& help_list = help_menu_p->items(); image_p = manage(new Gtk::Image(about_pixbuf_r)); help_list.push_back(ImageMenuElem(gettext("About efax-_gtk"), *image_p, sigc::bind(sigc::mem_fun(*this, &MainWindow::about_slot), true))); image_p = manage(new Gtk::Image(about_pixbuf_r)); help_list.push_back(ImageMenuElem(gettext("About _efax"), *image_p, sigc::bind(sigc::mem_fun(*this, &MainWindow::about_slot), false))); help_list.push_back(MenuElem(gettext("_Translations"), sigc::mem_fun(*this, &MainWindow::translations_slot))); help_list.push_back(SeparatorElem()); image_p = manage(new Gtk::Image(Gtk::Stock::HELP, Gtk::ICON_SIZE_MENU)); help_list.push_back(ImageMenuElem(gettext("_Help"), *image_p, sigc::mem_fun(*this, &MainWindow::helpfile_slot))); // now fill the menu bar MenuList& bar_list = menu_bar.items(); bar_list.push_front(MenuElem(gettext("_Help"), *help_menu_p)); bar_list.push_front(MenuElem(gettext("_File"), *file_menu_p)); } window_box.pack_start(menu_bar, false, false); window_box.pack_start(win_table, true, true); window_box.pack_start(status_line, false, false); add(window_box); win_table.set_border_width(standard_size/3); std::vector<Gtk::Widget*> focus_chain; focus_chain.push_back(&file_entry_frame); focus_chain.push_back(&number_box); focus_chain.push_back(&send_button); focus_chain.push_back(&receive_answer_button); focus_chain.push_back(&receive_takeover_button); focus_chain.push_back(&receive_standby_button); focus_chain.push_back(&stop_button); win_table.set_focus_chain(focus_chain); drawing_area.set_size_request(standard_size, standard_size); efax_controller.ready_to_quit_notify.connect(sigc::mem_fun(*this, &MainWindow::quit_slot)); Glib::signal_timeout().connect(sigc::mem_fun(*this, &MainWindow::timer_event_handler), TIMER_INTERVAL); Glib::signal_io().connect(sigc::mem_fun(*this, &MainWindow::read_error_slot), error_pipe.get_read_fd(), Glib::IO_IN); efax_controller.stdout_message.connect(sigc::mem_fun(text_window, &MessageText::write_black_slot)); efax_controller.write_state.connect(sigc::mem_fun(status_line, &StatusLine::write_status)); efax_controller.remove_from_socket_server_filelist.connect(sigc::mem_fun(*this, &MainWindow::remove_from_socket_server_filelist)); drawing_area.signal_expose_event().connect(sigc::mem_fun(*this, &MainWindow::draw_fax_from_socket_notifier), false); // we want to minimise the effect on efax, so make writing to the error pipe non-blocking error_pipe.make_write_non_block(); set_icon(prog_config.window_icon_r); set_file_items_sensitive_slot(); get_window_settings(); if (filename) { // this will also call set_file_items_sensitive_slot() if the call to // get_window_settings has set socket_button active file_button.set_active(true); file_entry.set_text(filename); set_focus(number_entry); } else set_focus(single_file_button); // now we will either show everything, or realise the window // and its children and keep it hidden in the system tray if (start_hidden) { realize(); show_all_children(true); hide(); Glib::signal_timeout().connect(sigc::mem_fun(*this, &MainWindow::start_hidden_check_handler), 5000); } else show_all(); if (!messages.empty()) { text_window.write_red_slot(messages.c_str()); text_window.write_red_slot("\n\n"); } // make sure that we have the faxin, faxout, faxsent, faxin/oldfax and faxsent/oldfax directories chdir(prog_config.working_dir.c_str()); mkdir("faxin", S_IRUSR | S_IWUSR | S_IXUSR); mkdir("faxout", S_IRUSR | S_IWUSR | S_IXUSR); mkdir("faxsent", S_IRUSR | S_IWUSR | S_IXUSR); mkdir("faxin/oldfax", S_IRUSR | S_IWUSR | S_IXUSR); mkdir("faxsent/oldfax", S_IRUSR | S_IWUSR | S_IXUSR); // set the working directory for the parent process chdir("faxin"); // if there is no config file installed, then bring up the settings dialog if (!prog_config.found_rcfile) { // we don't want to use MainWindow::settings_slot(), or the absence of // a configuration file will be reported twice -- not a big deal, but ... // so pass true as the last parameter to skip detection of settings file SettingsDialog dialog(standard_size, *this, true); dialog.accepted.connect(sigc::mem_fun(*this, &MainWindow::settings_changed_slot)); dialog.exec(); } // this connects the stdout facilities of Socket_server to MessageText socket_server.stdout_message.connect(sigc::mem_fun(text_window, &MessageText::write_black_slot)); // this connects the SigC object in Socket_server to a method in this class // which will update the Socket_list object (if such a dialog is displayed) socket_server.filelist_changed_notify.connect(sigc::mem_fun(*this, &MainWindow::socket_filelist_changed_notify_slot)); // and this connects the SigC object which indicates a fax has been received // from the socket for sending to the method which will pop up a "fax to send"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -