├── .gitignore ├── AUTHORS ├── COPYING ├── ChangeLog ├── Makefile.am ├── NEWS ├── README ├── README.md ├── autogen.sh ├── configure.ac ├── data ├── Makefile.am ├── gnethogs.desktop └── icons │ ├── Makefile.am │ └── hicolor │ ├── 16x16 │ └── apps │ │ └── gnethogs.png │ ├── 22x22 │ └── apps │ │ └── gnethogs.png │ ├── 24x24 │ └── apps │ │ └── gnethogs.png │ ├── 32x32 │ └── apps │ │ └── gnethogs.png │ └── 48x48 │ └── apps │ └── gnethogs.png ├── po ├── LINGUAS ├── POTFILES.in └── fr.po ├── src ├── MainWindow.cpp ├── MainWindow.h ├── Makefile.am ├── PendingUpdates.cpp ├── PendingUpdates.h ├── Tools.h ├── TreeData.h ├── gettext.h └── main.cpp └── ui ├── app.gresources.xml ├── appmenu.ui ├── headerbar.ui └── window.glade /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | codelite 3 | Makefile 4 | config.log 5 | config.status 6 | *.gmo 7 | *.o 8 | stamp-h1 9 | autom4te.cache/ 10 | src/gnethogs 11 | po/stamp-po 12 | src/.deps/ 13 | ABOUT-NLS 14 | INSTALL 15 | Makefile.in 16 | aclocal.m4 17 | compile 18 | config.guess 19 | config.h 20 | config.h.in 21 | config.rpath 22 | config.sub 23 | configure 24 | data/Makefile.in 25 | data/icons/Makefile.in 26 | depcomp 27 | install-sh 28 | intltool-extract.in 29 | intltool-merge.in 30 | intltool-update.in 31 | m4/ 32 | missing 33 | po/Makefile.in 34 | po/Makefile.in.in 35 | po/Makevars.template 36 | po/POTFILES 37 | po/Rules-quot 38 | po/boldquot.sed 39 | po/en@boldquot.header 40 | po/en@quot.header 41 | po/insert-header.sin 42 | po/quot.sed 43 | po/remove-potcdate.sin 44 | po/stamp-it 45 | src/Makefile.in 46 | mkinstalldirs 47 | src/gresources.c 48 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Developer 2 | --------- 3 | Mohamed Boussaffa (mbfoss@fastmail.com) 4 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | /usr/share/automake-1.16/COPYING -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mbfoss/gnethogs/bb69c6f82e059a451174c24a6bb1a21b32173f6c/ChangeLog -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = data src po 2 | 3 | dist_doc_DATA = \ 4 | README \ 5 | COPYING \ 6 | AUTHORS \ 7 | ChangeLog \ 8 | INSTALL \ 9 | NEWS 10 | 11 | INTLTOOL_FILES = intltool-extract.in \ 12 | intltool-merge.in \ 13 | intltool-update.in 14 | 15 | EXTRA_DIST = config.rpath m4/ChangeLog \ 16 | //$(INTLTOOL_FILES) 17 | 18 | DISTCLEANFILES = intltool-extract \ 19 | intltool-merge \ 20 | intltool-update 21 | 22 | ACLOCAL_AMFLAGS = -I m4 23 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mbfoss/gnethogs/bb69c6f82e059a451174c24a6bb1a21b32173f6c/NEWS -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mbfoss/gnethogs/bb69c6f82e059a451174c24a6bb1a21b32173f6c/README -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is a desktop graphical application for [nethogs](https://github.com/raboof/nethogs). 2 | Gnethogs uses libnethogs which is built from source by following the instructions below. 3 | 4 | ## Screenshot 5 | 6 | ![Screenshot](https://cloud.githubusercontent.com/assets/6733770/16925237/a1363dd0-4cf9-11e6-81aa-83a52e72c549.png) 7 | 8 | ## Installation 9 | 10 | To build form source and install: 11 | * install dependencies: 12 | * Debian/Ubuntu: `apt-get install build-essential libncurses5-dev libpcap-dev libgtkmm-3.0-dev autoconf autopoint intltool libxml2-utils` 13 | * Yum-based distros: `yum install gcc-c++ libpcap-devel.x86_64 libpcap.x86_64 ncurses* gtkmm30-docs autoconf autopoint intltool libxml2-utils` 14 | * `cd ~` 15 | * `git clone https://github.com/raboof/nethogs.git` 16 | * `git clone https://github.com/mbfoss/gnethogs.git` 17 | * `cd ~/nethogs && make libnethogs && sudo make install_dev` 18 | * `cd ~/gnethogs && ./autogen.sh && ./configure && make && sudo make install` 19 | * `sudo setcap cap_net_raw+ep /usr/local/bin/gnethogs` (To be able to run it as non-root user) 20 | * Seach `nethogs` in your application/activity menu! 21 | 22 | To uninstall: 23 | * `cd ~/nethogs && sudo make uninstall` 24 | * `cd ~/gnethogs && sudo make uninstall` 25 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | ### AUTOTOOLS ####################################################### 2 | # Runs autoconf, autoheader, aclocal, automake, autopoint, libtoolize 3 | echo "Regenerating autotools files" 4 | autoreconf --install --force --symlink || exit 1 5 | 6 | ### INTLTOOL ######################################################## 7 | # Run after autopoint or glib-gettextize 8 | echo "Setting up intltool" 9 | intltoolize --copy --force --automake || exit 1 10 | 11 | echo "Now run ./configure, make, and make install." 12 | 13 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT([gnethogs],[0.1]) 2 | 3 | AC_CONFIG_HEADERS([config.h]) 4 | 5 | AM_INIT_AUTOMAKE([1.14]) 6 | 7 | AM_SILENT_RULES([yes]) 8 | 9 | AC_PROG_CXX 10 | AC_PROG_CC 11 | 12 | AC_PATH_PROG([GLIB_COMPILE_RESOURCES], [glib-compile-resources]) 13 | 14 | PKG_CHECK_MODULES(GNETHOGS, [gtkmm-3.0 ]) 15 | 16 | 17 | # check for pthread 18 | PTHREAD_LIBS=error 19 | AC_CHECK_LIB(pthread, pthread_attr_init, PTHREAD_LIBS="-lpthread") 20 | if test "x$PTHREAD_LIBS" = xerror; then 21 | AC_CHECK_LIB(pthreads, pthread_attr_init, PTHREAD_LIBS="-lpthreads") 22 | fi 23 | if test "x$PTHREAD_LIBS" = xerror; then 24 | AC_CHECK_LIB(c_r, pthread_attr_init, PTHREAD_LIBS="-lc_r") 25 | fi 26 | if test "x$PTHREAD_LIBS" = xerror; then 27 | AC_CHECK_FUNC(pthread_attr_init, PTHREAD_LIBS="") 28 | fi 29 | AC_SUBST(PTHREAD_LIBS) 30 | 31 | #check for libnethogs 32 | 33 | AC_CHECK_LIB(nethogs, nethogsmonitor_loop, [], [ 34 | echo "Error! You need to have libnethogs-dev installed." 35 | exit -1 36 | ]) 37 | 38 | AC_LANG_PUSH([C++]) 39 | AC_CHECK_HEADERS([libnethogs.h]) 40 | AC_LANG_POP 41 | 42 | IT_PROG_INTLTOOL([0.35.0]) # Intltool 43 | AM_GNU_GETTEXT([external]) 44 | AM_GNU_GETTEXT_VERSION([0.13]) 45 | 46 | AC_CONFIG_FILES([ 47 | Makefile 48 | src/Makefile 49 | data/Makefile 50 | data/icons/Makefile 51 | po/Makefile.in 52 | ]) 53 | AC_OUTPUT 54 | 55 | -------------------------------------------------------------------------------- /data/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = icons 2 | 3 | # Desktop launcher and description file. 4 | desktopdir = $(datadir)/applications 5 | desktop_DATA = gnethogs.desktop 6 | 7 | -------------------------------------------------------------------------------- /data/gnethogs.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Version=1.0 3 | Type=Application 4 | Name=Nethogs Network Monitor 5 | Exec=gnethogs 6 | Comment=Per-application bandwidth usage statistics 7 | Icon=gnethogs 8 | Terminal=false 9 | Categories=Utility;Viewer;GTK; 10 | -------------------------------------------------------------------------------- /data/icons/Makefile.am: -------------------------------------------------------------------------------- 1 | iconsdir = $(datadir)/icons 2 | 3 | nobase_dist_icons_DATA = \ 4 | hicolor/16x16/apps/gnethogs.png \ 5 | hicolor/22x22/apps/gnethogs.png \ 6 | hicolor/24x24/apps/gnethogs.png \ 7 | hicolor/32x32/apps/gnethogs.png \ 8 | hicolor/48x48/apps/gnethogs.png 9 | 10 | gtk_update_icon_cache = gtk-update-icon-cache -f -t $(datadir)/icons/hicolor 11 | 12 | install-data-hook: update-icon-cache 13 | uninstall-hook: update-icon-cache 14 | update-icon-cache: 15 | @-if test -z "$(DESTDIR)"; then \ 16 | echo "Updating Gtk icon cache."; \ 17 | $(gtk_update_icon_cache); \ 18 | else \ 19 | echo "*** Icon cache not updated. After (un)install, run this:"; \ 20 | echo "*** $(gtk_update_icon_cache)"; \ 21 | fi 22 | -------------------------------------------------------------------------------- /data/icons/hicolor/16x16/apps/gnethogs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mbfoss/gnethogs/bb69c6f82e059a451174c24a6bb1a21b32173f6c/data/icons/hicolor/16x16/apps/gnethogs.png -------------------------------------------------------------------------------- /data/icons/hicolor/22x22/apps/gnethogs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mbfoss/gnethogs/bb69c6f82e059a451174c24a6bb1a21b32173f6c/data/icons/hicolor/22x22/apps/gnethogs.png -------------------------------------------------------------------------------- /data/icons/hicolor/24x24/apps/gnethogs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mbfoss/gnethogs/bb69c6f82e059a451174c24a6bb1a21b32173f6c/data/icons/hicolor/24x24/apps/gnethogs.png -------------------------------------------------------------------------------- /data/icons/hicolor/32x32/apps/gnethogs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mbfoss/gnethogs/bb69c6f82e059a451174c24a6bb1a21b32173f6c/data/icons/hicolor/32x32/apps/gnethogs.png -------------------------------------------------------------------------------- /data/icons/hicolor/48x48/apps/gnethogs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mbfoss/gnethogs/bb69c6f82e059a451174c24a6bb1a21b32173f6c/data/icons/hicolor/48x48/apps/gnethogs.png -------------------------------------------------------------------------------- /po/LINGUAS: -------------------------------------------------------------------------------- 1 | fr 2 | -------------------------------------------------------------------------------- /po/POTFILES.in: -------------------------------------------------------------------------------- 1 | # List of source files which contain translatable strings. 2 | 3 | src/main.cpp 4 | src/MainWindow.cpp 5 | src/MainWindow.h 6 | src/Tools.h 7 | src/TreeData.h 8 | src/PendingUpdates.cpp 9 | src/PendingUpdates.h 10 | ui/window.glade 11 | ui/appmenu.ui 12 | ui/headerbar.ui 13 | 14 | -------------------------------------------------------------------------------- /po/fr.po: -------------------------------------------------------------------------------- 1 | # French translations for gnethogs package 2 | # Traductions françaises du paquet gnethogs. 3 | # Copyright (C) 2016 Free Software Foundation, Inc. 4 | # This file is distributed under the same license as the gnethogs package. 5 | # momo , 2016. 6 | # 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: gnethogs 0.1\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2016-03-14 14:57+0800\n" 12 | "PO-Revision-Date: 2016-03-08 08:32+0800\n" 13 | "Last-Translator: momo \n" 14 | "Language-Team: French\n" 15 | "Language: fr\n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Plural-Forms: nplurals=2; plural=(n > 1);\n" 20 | 21 | #: src/MainWindow.cpp:31 22 | msgid "Failed to access network device(s)." 23 | msgstr "Impossible de démarrer la capture réseau." 24 | 25 | #: src/MainWindow.cpp:102 26 | #, c-format 27 | msgid "Sent: %s" 28 | msgstr "Envoyés: %s" 29 | 30 | #: src/MainWindow.cpp:105 31 | #, c-format 32 | msgid "Received: %s" 33 | msgstr "Reçus: %s" 34 | 35 | #: src/MainWindow.cpp:108 36 | #, c-format 37 | msgid "Outbound: %s" 38 | msgstr "Sortant: %s" 39 | 40 | #: src/MainWindow.cpp:111 41 | #, c-format 42 | msgid "Inbound: %s" 43 | msgstr "Entrant: %s" 44 | 45 | #: src/MainWindow.cpp:182 46 | msgid "Per-application bandwidth usage statistics." 47 | msgstr "Utilisatin de la bande passante par application." 48 | 49 | #: src/TreeData.h:90 50 | msgid "Name" 51 | msgstr "Nom" 52 | 53 | #: src/TreeData.h:91 54 | msgid "Device" 55 | msgstr "périphérique" 56 | 57 | #: src/TreeData.h:92 58 | msgid "User" 59 | msgstr "Utilisateur" 60 | 61 | #: src/TreeData.h:94 62 | msgid "Process ID" 63 | msgstr "ID du processus" 64 | 65 | #: src/TreeData.h:100 66 | msgid "Sent" 67 | msgstr "Envoyés" 68 | 69 | #: src/TreeData.h:106 70 | msgid "Received" 71 | msgstr "Reçus" 72 | 73 | #: src/TreeData.h:112 74 | msgid "Outboud" 75 | msgstr "Sortant" 76 | 77 | #: src/TreeData.h:118 78 | msgid "Inbound" 79 | msgstr "Entrant" 80 | 81 | #: ui/appmenu.ui:7 82 | msgid "About" 83 | msgstr "À propos" 84 | 85 | #: ui/appmenu.ui:11 86 | msgid "Quit" 87 | msgstr "Quitter" 88 | 89 | #: ui/headerbar.ui:9 90 | msgid "NetHogs Network Monitor" 91 | msgstr "Moniteur réseau NetHogs" 92 | -------------------------------------------------------------------------------- /src/MainWindow.cpp: -------------------------------------------------------------------------------- 1 | #include "gettext.h" 2 | #include "MainWindow.h" 3 | #include "PendingUpdates.h" 4 | #include 5 | #include 6 | #include 7 | 8 | class RefPtr; 9 | template 10 | static std::shared_ptr 11 | loadWiget(Glib::RefPtr& builder, const char* name) 12 | { 13 | T* ptr = nullptr; 14 | builder->get_widget(name, ptr); 15 | assert(ptr); 16 | return std::shared_ptr(ptr); 17 | } 18 | 19 | 20 | MainWindow::MainWindow() 21 | { 22 | } 23 | 24 | MainWindow::~MainWindow() 25 | { 26 | } 27 | 28 | bool MainWindow::onTimer() 29 | { 30 | if( PendingUpdates::getNetHogsMonitorStatus() != NETHOGS_STATUS_OK ) 31 | { 32 | char const* fail_msg = _("Failed to access network device(s)."); 33 | std::ostringstream oss; 34 | oss << "" << fail_msg << ""; 35 | m_p_status_label_1->set_markup(oss.str()); 36 | 37 | return false; //stops the timer 38 | } 39 | 40 | PendingUpdates::Update update; 41 | 42 | while(PendingUpdates::getRowUpdate(update)) 43 | { 44 | //update row data map and list store 45 | std::cout << "name" << update.record.name << " pid:" << update.record.pid << "\n"; 46 | auto it = m_rows_data.lower_bound(update.record.record_id); 47 | bool const existing = (it != m_rows_data.end() && it->first == update.record.record_id); 48 | 49 | if( update.action == NETHOGS_APP_ACTION_REMOVE ) 50 | { 51 | /*if( existing ) 52 | { 53 | m_list_store->erase(it->second.list_item_it); 54 | m_rows_data.erase(update.record.record_id); 55 | }*/ 56 | } 57 | else 58 | { 59 | Gtk::ListStore::iterator ls_it; 60 | if( existing ) 61 | { 62 | ls_it = it->second.list_item_it; 63 | } 64 | else 65 | { 66 | ls_it = m_list_store->append(); 67 | it = m_rows_data.insert(it, std::make_pair(update.record.record_id, RowData(ls_it))); 68 | //set fixed fields 69 | (*ls_it)[m_tree_data.pid ] = update.record.pid; 70 | std::cout << "***********PID********" << (*ls_it)[m_tree_data.pid ] << "\n"; 71 | (*ls_it)[m_tree_data.name] = getFileName(update.record.name); 72 | (*ls_it)[m_tree_data.path] = update.record.name; 73 | (*ls_it)[m_tree_data.icon] = Glib::wrap(gtk_icon_theme_load_icon (gtk_icon_theme_get_default (), getFileName(update.record.name).c_str(), 16, (GtkIconLookupFlags)(GTK_ICON_LOOKUP_USE_BUILTIN | GTK_ICON_LOOKUP_FORCE_SIZE), NULL)); 74 | } 75 | 76 | //update other fields 77 | (*ls_it)[m_tree_data.device_name] = update.record.device_name; 78 | (*ls_it)[m_tree_data.uid ] = update.record.pid?gtUserName(update.record.uid):""; 79 | (*ls_it)[m_tree_data.sent_bytes ] = update.record.sent_bytes; 80 | (*ls_it)[m_tree_data.recv_bytes ] = update.record.recv_bytes; 81 | (*ls_it)[m_tree_data.sent_kbs ] = update.record.sent_kbs; 82 | (*ls_it)[m_tree_data.recv_kbs ] = update.record.recv_kbs; 83 | 84 | //update total stats 85 | m_total_data.sent_bytes += (update.record.sent_bytes - it->second.sent_bytes); 86 | m_total_data.recv_bytes += (update.record.recv_bytes - it->second.recv_bytes); 87 | 88 | //save stat data 89 | it->second.sent_bytes = update.record.sent_bytes; 90 | it->second.recv_bytes = update.record.recv_bytes; 91 | it->second.sent_kbs = update.record.sent_kbs; 92 | it->second.recv_kbs = update.record.recv_kbs; 93 | } 94 | } 95 | 96 | //update total stats 97 | m_total_data.sent_kbs = 0; 98 | m_total_data.recv_kbs = 0; 99 | for(auto const& v : m_rows_data) 100 | { 101 | m_total_data.sent_kbs += v.second.sent_kbs; 102 | m_total_data.recv_kbs += v.second.recv_kbs; 103 | } 104 | 105 | char buffer[30]; 106 | 107 | snprintf(buffer, sizeof(buffer), _("Sent: %s"), formatByteCount(m_total_data.sent_bytes).c_str()); 108 | m_p_status_label_1->set_label(buffer); 109 | 110 | snprintf(buffer, sizeof(buffer), _("Received: %s"), formatByteCount(m_total_data.recv_bytes).c_str()); 111 | m_p_status_label_2->set_label(buffer); 112 | 113 | snprintf(buffer, sizeof(buffer), _("Outbound: %s"), formatBandwidth(m_total_data.sent_kbs).c_str()); 114 | m_p_status_label_3->set_label(buffer); 115 | 116 | snprintf(buffer, sizeof(buffer), _("Inbound: %s"), formatBandwidth(m_total_data.recv_kbs).c_str()); 117 | m_p_status_label_4->set_label(buffer); 118 | 119 | return true; 120 | } 121 | 122 | void MainWindow::onLoaded() 123 | { 124 | if( !m_timer_connection.connected() ) 125 | { 126 | m_timer_connection = Glib::signal_timeout().connect_seconds(sigc::bind(&MainWindow::onTimer, this), 1); 127 | } 128 | } 129 | 130 | bool MainWindow::onClosed(GdkEventAny*) 131 | { 132 | m_timer_connection.disconnect(); 133 | return false; 134 | } 135 | 136 | void MainWindow::run(Glib::RefPtr app) 137 | { 138 | Glib::RefPtr builder = Gtk::Builder::create(); 139 | 140 | try{ 141 | builder->add_from_resource("/nethogs_gui/window.glade"); 142 | } 143 | catch(Gtk::BuilderError const& e){ 144 | std::cout << e.what() << std::endl; 145 | return; 146 | } 147 | try{ 148 | builder->add_from_resource("/nethogs_gui/headerbar.ui"); 149 | } 150 | catch(Gtk::BuilderError const& e){ 151 | std::cout << e.what() << std::endl; 152 | return; 153 | } 154 | 155 | //get widgets 156 | m_window = loadWiget(builder, "main_window"); 157 | m_p_status_label_1 = loadWiget(builder, "status_label_1"); 158 | m_p_status_label_2 = loadWiget(builder, "status_label_2"); 159 | m_p_status_label_3 = loadWiget(builder, "status_label_3"); 160 | m_p_status_label_4 = loadWiget(builder, "status_label_4"); 161 | 162 | std::shared_ptr tree_view = loadWiget(builder, "treeview"); 163 | std::shared_ptr pheaderbar = loadWiget(builder, "headerbar"); 164 | 165 | //set title bar 166 | m_window->set_titlebar(*pheaderbar); 167 | 168 | //Create the Tree model 169 | m_list_store = m_tree_data.createListStore(); 170 | assert(m_list_store); 171 | tree_view->set_model(m_list_store); 172 | m_tree_data.setTreeColumns(tree_view.get()); 173 | 174 | //Connect signals 175 | m_window->signal_realize().connect(std::bind(&MainWindow::onLoaded, this)); 176 | m_window->signal_delete_event().connect(sigc::mem_fun(this,&MainWindow::onClosed)); 177 | m_window->signal_show().connect(sigc::mem_fun(this,&MainWindow::onShow)); 178 | 179 | //add actions 180 | app->add_action("about", sigc::mem_fun(this,&MainWindow::onAction_About)); 181 | app->add_action("quit", sigc::mem_fun(this,&MainWindow::onAction_Quit)); 182 | 183 | app->run(*m_window); 184 | } 185 | 186 | void MainWindow::onShow() 187 | { 188 | } 189 | 190 | void MainWindow::onAction_About() 191 | { 192 | Gtk::AboutDialog dlg; 193 | 194 | dlg.set_transient_for(*m_window); 195 | dlg.set_program_name(PACKAGE_NAME); 196 | dlg.set_version(PACKAGE_VERSION); 197 | dlg.set_logo_icon_name("gnethogs"), 198 | dlg.set_comments(_("Per-application bandwidth usage statistics.")); 199 | dlg.set_authors({"Mohamed Boussaffa"}); 200 | dlg.set_license_type(Gtk::LICENSE_GPL_3_0); 201 | dlg.run(); 202 | } 203 | 204 | void MainWindow::onAction_Quit() 205 | { 206 | m_window->close(); 207 | } 208 | -------------------------------------------------------------------------------- /src/MainWindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #include "Tools.h" 5 | #include "TreeData.h" 6 | #include "PendingUpdates.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | class MainWindow 16 | { 17 | struct RowData 18 | { 19 | RowData(Gtk::ListStore::iterator const& ls_it = Gtk::ListStore::iterator()) 20 | : list_item_it(ls_it), sent_bytes(0), recv_bytes(0), sent_kbs(0), recv_kbs(0) 21 | { 22 | } 23 | Gtk::ListStore::iterator list_item_it; 24 | uint32_t sent_bytes; 25 | uint32_t recv_bytes; 26 | float sent_kbs; 27 | float recv_kbs; 28 | }; 29 | 30 | public: 31 | MainWindow(); 32 | ~MainWindow(); 33 | 34 | void run(Glib::RefPtr app); 35 | 36 | 37 | private: 38 | bool onTimer(); 39 | void onLoaded(); 40 | bool onClosed(GdkEventAny*); 41 | void onShow(); 42 | 43 | void onAction_About(); 44 | void onAction_Quit(); 45 | 46 | private: 47 | std::shared_ptr m_window; 48 | std::shared_ptr m_p_status_label_1; 49 | std::shared_ptr m_p_status_label_2; 50 | std::shared_ptr m_p_status_label_3; 51 | std::shared_ptr m_p_status_label_4; 52 | Glib::RefPtr m_list_store; 53 | std::map m_rows_data; 54 | RowData m_total_data; 55 | TreeData m_tree_data; 56 | sigc::connection m_timer_connection; 57 | }; 58 | 59 | #endif // MAINWINDOW_H 60 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CPPFLAGS = \ 2 | -DPACKAGE_LOCALE_DIR=\""$(localedir)"\" \ 3 | -DPACKAGE_SRC_DIR=\""$(srcdir)"\" \ 4 | -DPACKAGE_DATA_DIR=\""$(pkgdatadir)"\" \ 5 | $(GNETHOGS_CFLAGS) 6 | 7 | AM_CFLAGS =\ 8 | -Wall\ 9 | -g 10 | 11 | bin_PROGRAMS = gnethogs 12 | 13 | gnethogs_SOURCES = \ 14 | main.cpp \ 15 | gresources.c \ 16 | gettext.h \ 17 | TreeData.h \ 18 | MainWindow.cpp \ 19 | MainWindow.h \ 20 | PendingUpdates.cpp \ 21 | PendingUpdates.h 22 | 23 | gnethogs_LDFLAGS = -lnethogs 24 | gnethogs_CXXFLAGS = --std=c++11 25 | 26 | gnethogs_LDADD = $(GNETHOGS_LIBS) $(PTHREAD_LIBS) 27 | 28 | ui_dir = ../ui/ 29 | ui_gresource = ../ui/app.gresources.xml 30 | ui_deps = \ 31 | $(ui_dir)/appmenu.ui \ 32 | $(ui_dir)/headerbar.ui \ 33 | $(ui_dir)/window.glade 34 | 35 | gresources.c: $(ui_gresource) $(ui_deps) 36 | $(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) --generate-source --sourcedir=$(ui_dir) $(ui_gresource) --target=$@ 37 | -------------------------------------------------------------------------------- /src/PendingUpdates.cpp: -------------------------------------------------------------------------------- 1 | #include "PendingUpdates.h" 2 | #include 3 | 4 | std::mutex PendingUpdates::m_mutex; 5 | PendingUpdates::RowUpdatesMap PendingUpdates::m_row_updates_map; 6 | int PendingUpdates::m_nethogs_monitor_status = NETHOGS_STATUS_OK; 7 | 8 | void PendingUpdates::setRowUpdate(int action, NethogsMonitorRecord const& record) 9 | { 10 | if( action == NETHOGS_APP_ACTION_REMOVE || record.sent_bytes || record.recv_bytes ) 11 | { 12 | //save the update for GUI use 13 | std::lock_guard lock(m_mutex); 14 | Update update; 15 | memset(&update, 0, sizeof(update)); 16 | update.action = action; 17 | update.record = record; 18 | m_row_updates_map[record.record_id] = update; 19 | } 20 | } 21 | 22 | bool PendingUpdates::getRowUpdate(PendingUpdates::Update& update) 23 | { 24 | std::lock_guard lock(m_mutex); 25 | if( m_row_updates_map.empty() ) 26 | return false; 27 | update = m_row_updates_map.begin()->second; 28 | m_row_updates_map.erase(m_row_updates_map.begin()); 29 | return true; 30 | } 31 | 32 | void PendingUpdates::setNetHogsMonitorStatus(int status) 33 | { 34 | std::lock_guard lock(m_mutex); 35 | m_nethogs_monitor_status = status; 36 | } 37 | 38 | int PendingUpdates::getNetHogsMonitorStatus() 39 | { 40 | std::lock_guard lock(m_mutex); 41 | return m_nethogs_monitor_status; 42 | } 43 | -------------------------------------------------------------------------------- /src/PendingUpdates.h: -------------------------------------------------------------------------------- 1 | #ifndef PENDINGUPDATES_H 2 | #define PENDINGUPDATES_H 3 | 4 | #include "libnethogs.h" 5 | #include 6 | #include 7 | 8 | class PendingUpdates final 9 | { 10 | PendingUpdates() = delete; 11 | 12 | public: 13 | struct Update 14 | { 15 | int action; 16 | NethogsMonitorRecord record; 17 | }; 18 | 19 | static void setRowUpdate(int action, NethogsMonitorRecord const& record); 20 | static void setNetHogsMonitorStatus(int status); 21 | 22 | static int getNetHogsMonitorStatus(); 23 | static bool getRowUpdate(Update& update); 24 | 25 | private: 26 | typedef std::map RowUpdatesMap; 27 | 28 | static std::mutex m_mutex; 29 | static RowUpdatesMap m_row_updates_map; 30 | static int m_nethogs_monitor_status; 31 | }; 32 | 33 | #endif // PENDINGUPDATES_H 34 | -------------------------------------------------------------------------------- /src/Tools.h: -------------------------------------------------------------------------------- 1 | #ifndef TOOLS_H 2 | #define TOOLS_H 3 | 4 | #include 5 | #include 6 | 7 | static inline std::string gtUserName(uint32_t uid) 8 | { 9 | struct passwd const *pwd = getpwuid(uid); 10 | if(pwd) return pwd->pw_name; 11 | return std::to_string(uid); 12 | } 13 | 14 | static inline std::string getFileName(const std::string& s) 15 | { 16 | const char sep = '/'; 17 | const size_t i = s.rfind(sep, s.length()); 18 | if (i != std::string::npos) { 19 | return(s.substr(i+1, s.length() - i)); 20 | } 21 | return(s); 22 | } 23 | 24 | static inline std::string formatByteCount(double v, const char** orders, int nb_orders) 25 | { 26 | int order = 0; 27 | while (v >= 1024 && order + 1 < nb_orders) { 28 | order++; 29 | v = v/1024; 30 | } 31 | char buffer1[30]; 32 | snprintf(buffer1, sizeof(buffer1), "%.2lf %s", v, orders[order]); 33 | return buffer1; 34 | } 35 | 36 | static inline std::string formatByteCount(double v) 37 | { 38 | static const char* orders[] = { "B", "KB", "MB", "GB" }; 39 | return formatByteCount(v, orders, sizeof(orders)/sizeof(orders[0])); 40 | } 41 | 42 | static inline std::string formatBandwidth(double v) 43 | { 44 | static const char* orders[] = { "KB/sec", "MB/sec", "GB/sec" }; 45 | return formatByteCount(v, orders, sizeof(orders)/sizeof(orders[0])); 46 | } 47 | 48 | #endif // TOOLS_H 49 | -------------------------------------------------------------------------------- /src/TreeData.h: -------------------------------------------------------------------------------- 1 | #ifndef TREE_MODEL_H 2 | #define TREE_MODEL_H 3 | 4 | #include 5 | #include 6 | #include "Tools.h" 7 | #include 8 | 9 | //Tree model columns 10 | class TreeData 11 | { 12 | public: 13 | TreeData() 14 | { 15 | 16 | } 17 | 18 | Glib::RefPtr createListStore() 19 | { 20 | Gtk::TreeModel::ColumnRecord column_record; 21 | column_record.add(name); 22 | column_record.add(device_name); 23 | column_record.add(uid); 24 | column_record.add(pid); 25 | column_record.add(icon); 26 | column_record.add(sent_bytes); 27 | column_record.add(recv_bytes); 28 | column_record.add(sent_kbs); 29 | column_record.add(recv_kbs); 30 | column_record.add(path); 31 | column_record.add(icon) ; 32 | return Gtk::ListStore::create(column_record); 33 | } 34 | 35 | static void pid_CellDataFun(Gtk::CellRenderer* renderer, 36 | const Gtk::TreeModel::iterator& iter, 37 | int model_column) 38 | { 39 | Gtk::CellRendererText* p_text_renderer = dynamic_cast(renderer); 40 | if(iter) 41 | { 42 | //Get the value from the model. 43 | Gtk::TreeModel::Row row = *iter; 44 | int32_t value = 0; 45 | row.get_value(model_column, value); 46 | if( !value ) 47 | { 48 | p_text_renderer->property_text() = ""; 49 | } 50 | } 51 | } 52 | 53 | static void byteCount_CellDataFun(Gtk::CellRenderer* renderer, 54 | const Gtk::TreeModel::iterator& iter, 55 | int model_column) 56 | { 57 | Gtk::CellRendererText* p_text_renderer = dynamic_cast(renderer); 58 | if(iter) 59 | { 60 | //Get the value from the model. 61 | Gtk::TreeModel::Row row = *iter; 62 | uint32_t value = 0; 63 | row.get_value(model_column, value); 64 | //Show the text representation in the view: 65 | p_text_renderer->property_text() = formatByteCount(value).c_str(); 66 | } 67 | } 68 | 69 | static void bandwidth_CellDataFun(Gtk::CellRenderer* renderer, 70 | const Gtk::TreeModel::iterator& iter, 71 | int model_column) 72 | { 73 | Gtk::CellRendererText* p_text_renderer = dynamic_cast(renderer); 74 | if(iter) 75 | { 76 | //Get the value from the model. 77 | Gtk::TreeModel::Row row = *iter; 78 | float value = 0; 79 | row.get_value(model_column, value); 80 | //Show the text representation in the view: 81 | p_text_renderer->property_text() = formatBandwidth(value).c_str(); 82 | } 83 | } 84 | 85 | void setTreeColumns(Gtk::TreeView* tree_view) 86 | { 87 | using namespace std::placeholders; 88 | 89 | Gtk::TreeView::Column* pcolumn = 0; 90 | int col = 0; 91 | 92 | tree_view->append_column(_("Icon"), icon); 93 | /*col = tree_view->get_n_columns() - 1; 94 | pcolumn = tree_view->get_column(col); 95 | pcolumn->set_cell_data_func(*pcolumn->get_cells().at(0), 96 | std::bind(&icon_CellDataFun, _1, _2, col));*/ 97 | 98 | tree_view->append_column(_("Name"), name); 99 | tree_view->append_column(_("Device"), device_name); 100 | tree_view->append_column(_("User"), uid); 101 | 102 | tree_view->append_column(_("Process ID"), pid); 103 | /*col = tree_view->get_n_columns() - 1; 104 | pcolumn = tree_view->get_column(col); 105 | pcolumn->set_cell_data_func(*pcolumn->get_cells().at(0), 106 | std::bind(&pid_CellDataFun, _1, _2, col));*/ 107 | 108 | tree_view->append_column(_("Sent"), sent_bytes); 109 | col = tree_view->get_n_columns() - 1; 110 | pcolumn = tree_view->get_column(col); 111 | pcolumn->set_cell_data_func(*pcolumn->get_cells().at(0), 112 | std::bind(&byteCount_CellDataFun, _1, _2, col)); 113 | 114 | tree_view->append_column(_("Received"), recv_bytes); 115 | col = tree_view->get_n_columns() - 1; 116 | pcolumn = tree_view->get_column(col); 117 | pcolumn->set_cell_data_func(*pcolumn->get_cells().at(0), 118 | std::bind(&byteCount_CellDataFun, _1, _2, col)); 119 | 120 | tree_view->append_column(_("Outboud"), sent_kbs); 121 | col = tree_view->get_n_columns() - 1; 122 | pcolumn = tree_view->get_column(col); 123 | pcolumn->set_cell_data_func(*pcolumn->get_cells().at(0), 124 | std::bind(&bandwidth_CellDataFun, _1, _2, col)); 125 | 126 | tree_view->append_column(_("Inbound"), recv_kbs); 127 | col = tree_view->get_n_columns() - 1; 128 | pcolumn = tree_view->get_column(col); 129 | pcolumn->set_cell_data_func(*pcolumn->get_cells().at(0), 130 | std::bind(&bandwidth_CellDataFun, _1, _2, col)); 131 | 132 | tree_view->set_tooltip_column(tree_view->get_n_columns() ); 133 | 134 | tree_view->append_column(_("Path"), path); 135 | 136 | for(int pos = 0; pos < tree_view->get_n_columns(); ++pos) 137 | { 138 | Gtk::TreeView::Column* pcolumn = tree_view->get_column(pos); 139 | pcolumn->set_sort_column(pos); 140 | } 141 | } 142 | 143 | Gtk::TreeModelColumn name; 144 | Gtk::TreeModelColumn device_name; 145 | Gtk::TreeModelColumn uid; 146 | Gtk::TreeModelColumn pid; 147 | Gtk::TreeModelColumn sent_bytes; 148 | Gtk::TreeModelColumn recv_bytes; 149 | Gtk::TreeModelColumn sent_kbs; 150 | Gtk::TreeModelColumn recv_kbs; 151 | Gtk::TreeModelColumn path; 152 | Gtk::TreeModelColumn > icon; 153 | //GtkWidget *image; 154 | }; 155 | 156 | #endif 157 | -------------------------------------------------------------------------------- /src/gettext.h: -------------------------------------------------------------------------------- 1 | /* Convenience header for conditional use of GNU . 2 | Copyright (C) 1995-1998, 2000-2002, 2004-2006, 2009-2011 Free Software Foundation, Inc. 3 | This program is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation; either version 3 of the License, or 6 | (at your option) any later version. 7 | This program is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | You should have received a copy of the GNU General Public License 12 | along with this program. If not, see . */ 13 | 14 | #ifndef _LIBGETTEXT_H 15 | #define _LIBGETTEXT_H 1 16 | 17 | #include "../config.h" 18 | 19 | 20 | /* NLS can be disabled through the configure --disable-nls option. */ 21 | #if ENABLE_NLS 22 | 23 | #define _(String) gettext (String) 24 | 25 | /* Get declarations of GNU message catalog functions. */ 26 | # include 27 | 28 | /* You can set the DEFAULT_TEXT_DOMAIN macro to specify the domain used by 29 | the gettext() and ngettext() macros. This is an alternative to calling 30 | textdomain(), and is useful for libraries. */ 31 | # ifdef DEFAULT_TEXT_DOMAIN 32 | # undef gettext 33 | # define gettext(Msgid) \ 34 | dgettext (DEFAULT_TEXT_DOMAIN, Msgid) 35 | # undef ngettext 36 | # define ngettext(Msgid1, Msgid2, N) \ 37 | dngettext (DEFAULT_TEXT_DOMAIN, Msgid1, Msgid2, N) 38 | # endif 39 | 40 | #else 41 | 42 | /* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which 43 | chokes if dcgettext is defined as a macro. So include it now, to make 44 | later inclusions of a NOP. We don't include 45 | as well because people using "gettext.h" will not include , 46 | and also including would fail on SunOS 4, whereas 47 | is OK. */ 48 | #if defined(__sun) 49 | # include 50 | #endif 51 | 52 | /* Many header files from the libstdc++ coming with g++ 3.3 or newer include 53 | , which chokes if dcgettext is defined as a macro. So include 54 | it now, to make later inclusions of a NOP. */ 55 | #if defined(__cplusplus) && defined(__GNUG__) && (__GNUC__ >= 3) 56 | # include 57 | # if (__GLIBC__ >= 2 && !defined __UCLIBC__) || _GLIBCXX_HAVE_LIBINTL_H 58 | # include 59 | # endif 60 | #endif 61 | 62 | /* Disabled NLS. 63 | The casts to 'const char *' serve the purpose of producing warnings 64 | for invalid uses of the value returned from these functions. 65 | On pre-ANSI systems without 'const', the config.h file is supposed to 66 | contain "#define const". */ 67 | # undef gettext 68 | # define gettext(Msgid) ((const char *) (Msgid)) 69 | # undef dgettext 70 | # define dgettext(Domainname, Msgid) ((void) (Domainname), gettext (Msgid)) 71 | # undef dcgettext 72 | # define dcgettext(Domainname, Msgid, Category) \ 73 | ((void) (Category), dgettext (Domainname, Msgid)) 74 | # undef ngettext 75 | # define ngettext(Msgid1, Msgid2, N) \ 76 | ((N) == 1 \ 77 | ? ((void) (Msgid2), (const char *) (Msgid1)) \ 78 | : ((void) (Msgid1), (const char *) (Msgid2))) 79 | # undef dngettext 80 | # define dngettext(Domainname, Msgid1, Msgid2, N) \ 81 | ((void) (Domainname), ngettext (Msgid1, Msgid2, N)) 82 | # undef dcngettext 83 | # define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ 84 | ((void) (Category), dngettext (Domainname, Msgid1, Msgid2, N)) 85 | # undef textdomain 86 | # define textdomain(Domainname) ((const char *) (Domainname)) 87 | # undef bindtextdomain 88 | # define bindtextdomain(Domainname, Dirname) \ 89 | ((void) (Domainname), (const char *) (Dirname)) 90 | # undef bind_textdomain_codeset 91 | # define bind_textdomain_codeset(Domainname, Codeset) \ 92 | ((void) (Domainname), (const char *) (Codeset)) 93 | 94 | #endif 95 | 96 | /* Prefer gnulib's setlocale override over libintl's setlocale override. */ 97 | #ifdef GNULIB_defined_setlocale 98 | # undef setlocale 99 | # define setlocale rpl_setlocale 100 | #endif 101 | 102 | /* A pseudo function call that serves as a marker for the automated 103 | extraction of messages, but does not call gettext(). The run-time 104 | translation is done at a different place in the code. 105 | The argument, String, should be a literal string. Concatenated strings 106 | and other string expressions won't work. 107 | The macro's expansion is not parenthesized, so that it is suitable as 108 | initializer for static 'char[]' or 'const char[]' variables. */ 109 | #define gettext_noop(String) String 110 | 111 | /* The separator between msgctxt and msgid in a .mo file. */ 112 | #define GETTEXT_CONTEXT_GLUE "\004" 113 | 114 | /* Pseudo function calls, taking a MSGCTXT and a MSGID instead of just a 115 | MSGID. MSGCTXT and MSGID must be string literals. MSGCTXT should be 116 | short and rarely need to change. 117 | The letter 'p' stands for 'particular' or 'special'. */ 118 | #ifdef DEFAULT_TEXT_DOMAIN 119 | # define pgettext(Msgctxt, Msgid) \ 120 | pgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) 121 | #else 122 | # define pgettext(Msgctxt, Msgid) \ 123 | pgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) 124 | #endif 125 | #define dpgettext(Domainname, Msgctxt, Msgid) \ 126 | pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) 127 | #define dcpgettext(Domainname, Msgctxt, Msgid, Category) \ 128 | pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, Category) 129 | #ifdef DEFAULT_TEXT_DOMAIN 130 | # define npgettext(Msgctxt, Msgid, MsgidPlural, N) \ 131 | npgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) 132 | #else 133 | # define npgettext(Msgctxt, Msgid, MsgidPlural, N) \ 134 | npgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) 135 | #endif 136 | #define dnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N) \ 137 | npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) 138 | #define dcnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N, Category) \ 139 | npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, Category) 140 | 141 | #ifdef __GNUC__ 142 | __inline 143 | #else 144 | #ifdef __cplusplus 145 | inline 146 | #endif 147 | #endif 148 | static const char * 149 | pgettext_aux (const char *domain, 150 | const char *msg_ctxt_id, const char *msgid, 151 | int category) 152 | { 153 | const char *translation = dcgettext (domain, msg_ctxt_id, category); 154 | if (translation == msg_ctxt_id) 155 | return msgid; 156 | else 157 | return translation; 158 | } 159 | 160 | #ifdef __GNUC__ 161 | __inline 162 | #else 163 | #ifdef __cplusplus 164 | inline 165 | #endif 166 | #endif 167 | static const char * 168 | npgettext_aux (const char *domain, 169 | const char *msg_ctxt_id, const char *msgid, 170 | const char *msgid_plural, unsigned long int n, 171 | int category) 172 | { 173 | const char *translation = 174 | dcngettext (domain, msg_ctxt_id, msgid_plural, n, category); 175 | if (translation == msg_ctxt_id || translation == msgid_plural) 176 | return (n == 1 ? msgid : msgid_plural); 177 | else 178 | return translation; 179 | } 180 | 181 | /* The same thing extended for non-constant arguments. Here MSGCTXT and MSGID 182 | can be arbitrary expressions. But for string literals these macros are 183 | less efficient than those above. */ 184 | 185 | #include 186 | 187 | #if (((__GNUC__ >= 3 || __GNUG__ >= 2) && !defined __STRICT_ANSI__) \ 188 | /* || __STDC_VERSION__ >= 199901L */ ) 189 | # define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 1 190 | #else 191 | # define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 0 192 | #endif 193 | 194 | #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 195 | #include 196 | #endif 197 | 198 | #define pgettext_expr(Msgctxt, Msgid) \ 199 | dcpgettext_expr (NULL, Msgctxt, Msgid, LC_MESSAGES) 200 | #define dpgettext_expr(Domainname, Msgctxt, Msgid) \ 201 | dcpgettext_expr (Domainname, Msgctxt, Msgid, LC_MESSAGES) 202 | 203 | #ifdef __GNUC__ 204 | __inline 205 | #else 206 | #ifdef __cplusplus 207 | inline 208 | #endif 209 | #endif 210 | static const char * 211 | dcpgettext_expr (const char *domain, 212 | const char *msgctxt, const char *msgid, 213 | int category) 214 | { 215 | size_t msgctxt_len = strlen (msgctxt) + 1; 216 | size_t msgid_len = strlen (msgid) + 1; 217 | const char *translation; 218 | #if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 219 | char msg_ctxt_id[msgctxt_len + msgid_len]; 220 | #else 221 | char buf[1024]; 222 | char *msg_ctxt_id = 223 | (msgctxt_len + msgid_len <= sizeof (buf) 224 | ? buf 225 | : (char *) malloc (msgctxt_len + msgid_len)); 226 | if (msg_ctxt_id != NULL) 227 | #endif 228 | { 229 | memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1); 230 | msg_ctxt_id[msgctxt_len - 1] = '\004'; 231 | memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len); 232 | translation = dcgettext (domain, msg_ctxt_id, category); 233 | #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 234 | if (msg_ctxt_id != buf) 235 | free (msg_ctxt_id); 236 | #endif 237 | if (translation != msg_ctxt_id) 238 | return translation; 239 | } 240 | return msgid; 241 | } 242 | 243 | #define npgettext_expr(Msgctxt, Msgid, MsgidPlural, N) \ 244 | dcnpgettext_expr (NULL, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES) 245 | #define dnpgettext_expr(Domainname, Msgctxt, Msgid, MsgidPlural, N) \ 246 | dcnpgettext_expr (Domainname, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES) 247 | 248 | #ifdef __GNUC__ 249 | __inline 250 | #else 251 | #ifdef __cplusplus 252 | inline 253 | #endif 254 | #endif 255 | static const char * 256 | dcnpgettext_expr (const char *domain, 257 | const char *msgctxt, const char *msgid, 258 | const char *msgid_plural, unsigned long int n, 259 | int category) 260 | { 261 | size_t msgctxt_len = strlen (msgctxt) + 1; 262 | size_t msgid_len = strlen (msgid) + 1; 263 | const char *translation; 264 | #if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 265 | char msg_ctxt_id[msgctxt_len + msgid_len]; 266 | #else 267 | char buf[1024]; 268 | char *msg_ctxt_id = 269 | (msgctxt_len + msgid_len <= sizeof (buf) 270 | ? buf 271 | : (char *) malloc (msgctxt_len + msgid_len)); 272 | if (msg_ctxt_id != NULL) 273 | #endif 274 | { 275 | memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1); 276 | msg_ctxt_id[msgctxt_len - 1] = '\004'; 277 | memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len); 278 | translation = dcngettext (domain, msg_ctxt_id, msgid_plural, n, category); 279 | #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS 280 | if (msg_ctxt_id != buf) 281 | free (msg_ctxt_id); 282 | #endif 283 | if (!(translation == msg_ctxt_id || translation == msgid_plural)) 284 | return translation; 285 | } 286 | return (n == 1 ? msgid : msgid_plural); 287 | } 288 | 289 | #endif /* _LIBGETTEXT_H */ 290 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "gettext.h" 2 | #include "MainWindow.h" 3 | #include "PendingUpdates.h" 4 | #include 5 | #include 6 | #include 7 | 8 | extern GResource *app_get_resource (void); 9 | 10 | //CALLBACK BY NETHOGS MONITOR 11 | static void onNethogsUpdate(int action, NethogsMonitorRecord const* update) 12 | { 13 | PendingUpdates::setRowUpdate(action, *update); 14 | } 15 | 16 | static void nethogsMonitorThreadProc() 17 | { 18 | const int status = nethogsmonitor_loop(&onNethogsUpdate, NULL, 1000); 19 | PendingUpdates::setNetHogsMonitorStatus(status); 20 | } 21 | 22 | static void onAppStartup(Glib::RefPtr & app) 23 | { 24 | Glib::RefPtr builder = Gtk::Builder::create(); 25 | builder->add_from_resource("/nethogs_gui/appmenu.ui"); 26 | //set app menu 27 | auto appmenu = Glib::RefPtr::cast_dynamic(builder->get_object("appmenu")); 28 | app->set_app_menu(appmenu); 29 | } 30 | 31 | int main(int argc, char* argv[]) 32 | { 33 | Gtk::Main kit(argc, argv); 34 | 35 | setlocale (LC_ALL, ""); 36 | textdomain (PACKAGE); 37 | bindtextdomain (PACKAGE, PACKAGE_LOCALE_DIR); 38 | 39 | //create app 40 | Glib::RefPtr app = 41 | Gtk::Application::create(argc, argv, "io.github.mb-gh.nethogs_gui"); 42 | 43 | std::thread nethogs_monitor_thread(&nethogsMonitorThreadProc); 44 | 45 | MainWindow w; 46 | 47 | app->signal_startup().connect(std::bind(&onAppStartup, std::ref(app))); 48 | 49 | w.run(app); 50 | 51 | nethogsmonitor_breakloop(); 52 | nethogs_monitor_thread.join(); 53 | 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /ui/app.gresources.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | window.glade 5 | appmenu.ui 6 | headerbar.ui 7 | 8 | 9 | -------------------------------------------------------------------------------- /ui/appmenu.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | 7 | About 8 | app.about 9 | 10 | 11 | Quit 12 | <Primary>q 13 | app.quit 14 | 15 |
16 |
17 |
18 | -------------------------------------------------------------------------------- /ui/headerbar.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | True 7 | False 8 | NetHogs Network Monitor 9 | 10 | True 11 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /ui/window.glade: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | False 7 | 8 | 1 9 | 600 10 | 400 11 | gnethogs 12 | 13 | 14 | True 15 | False 16 | vertical 17 | 18 | 19 | True 20 | True 21 | in 22 | 23 | 24 | List 25 | True 26 | True 27 | vertical 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | True 36 | True 37 | 0 38 | 39 | 40 | 41 | 42 | True 43 | False 44 | 1 45 | 46 | 47 | False 48 | True 49 | 1 50 | 51 | 52 | 53 | 54 | True 55 | False 56 | 57 | 58 | True 59 | False 60 | 0 61 | 2 62 | 63 | 64 | True 65 | True 66 | 0 67 | 68 | 69 | 70 | 71 | True 72 | False 73 | 0 74 | 2 75 | 76 | 77 | True 78 | True 79 | 1 80 | 81 | 82 | 83 | 84 | True 85 | False 86 | 0 87 | 2 88 | 89 | 90 | True 91 | True 92 | 2 93 | 94 | 95 | 96 | 97 | True 98 | False 99 | 0 100 | 2 101 | 102 | 103 | True 104 | True 105 | 3 106 | 107 | 108 | 109 | 110 | False 111 | True 112 | 2 113 | 114 | 115 | 116 | 117 | True 118 | False 119 | 1 120 | 121 | 122 | False 123 | True 124 | 3 125 | 126 | 127 | 128 | 129 | 130 | 131 | --------------------------------------------------------------------------------