1 /*
2  * Copyright (c) 2005-2006 Johannes Zellner, <webmaster@nebulon.de>
3  * Copyright (c) 2010 Mike Massonnet, <mmassonnet@xfce.org>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  */
10 
11 #ifdef HAVE_CONFIG_H
12 #include <config.h>
13 #endif
14 
15 #include <glib/gi18n.h>
16 #include <gtk/gtk.h>
17 #if GLIB_CHECK_VERSION(2, 28, 0)
18 #include <gio/gio.h>
19 #endif
20 
21 #include "settings.h"
22 #include "process-window.h"
23 #include "task-manager.h"
24 
25 static XtmSettings *settings;
26 static GtkWidget *window;
27 static GtkStatusIcon *status_icon_or_null = NULL;
28 static XtmTaskManager *task_manager;
29 static guint timeout = 0;
30 static gboolean start_hidden = FALSE;
31 
32 static GOptionEntry main_entries[] = {
33 	{ "start-hidden", 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE, &start_hidden, "Don't open a task manager window", NULL },
34 	{ NULL, 0, 0, 0, NULL, NULL, NULL }
35 };
36 
37 static void	destroy_window (void);
38 
39 
40 static void
status_icon_activated(void)41 status_icon_activated (void)
42 {
43 	if (!(gtk_widget_get_visible (window)))
44 		gtk_widget_show (window);
45 	else
46 		gtk_widget_hide (window);
47 }
48 
49 static void
status_icon_popup_menu(GtkStatusIcon * _status_icon,guint button,guint activate_time)50 status_icon_popup_menu (GtkStatusIcon *_status_icon, guint button, guint activate_time)
51 {
52 	static GtkWidget *menu = NULL;
53 
54 	if (menu == NULL)
55 	{
56 		GtkWidget *mi;
57 		menu = gtk_menu_new ();
58 		mi = gtk_image_menu_item_new_from_stock (GTK_STOCK_QUIT, NULL);
59 		g_signal_connect (mi, "activate", G_CALLBACK (destroy_window), NULL);
60 		gtk_container_add (GTK_CONTAINER (menu), mi);
61 		gtk_widget_show_all (menu);
62 	}
63 
64 	gtk_menu_popup (GTK_MENU (menu), NULL, NULL, gtk_status_icon_position_menu, _status_icon, button, activate_time);
65 }
66 
67 static void
create_status_icon(void)68 create_status_icon (void)
69 {
70 	if (!status_icon_or_null)
71 	{
72 		GtkStatusIcon *status_icon = gtk_status_icon_new_from_icon_name ("org.xfce.taskmanager");
73 		g_signal_connect (status_icon, "activate", G_CALLBACK (status_icon_activated), NULL);
74 		g_signal_connect (status_icon, "popup-menu", G_CALLBACK (status_icon_popup_menu), NULL);
75 		status_icon_or_null = status_icon;
76 	}
77 }
78 
79 static gboolean
status_icon_get_visible()80 status_icon_get_visible ()
81 {
82 	return status_icon_or_null && gtk_status_icon_get_visible (status_icon_or_null);
83 }
84 
85 static void
show_hide_status_icon(void)86 show_hide_status_icon (void)
87 {
88 	gboolean show_status_icon;
89 	g_object_get (settings, "show-status-icon", &show_status_icon, NULL);
90 	if (show_status_icon)
91 	{
92 		create_status_icon ();
93 		gtk_status_icon_set_visible (status_icon_or_null, TRUE);
94 	}
95 	else if (status_icon_get_visible ())
96 	{
97 		gtk_status_icon_set_visible (status_icon_or_null, FALSE);
98 	}
99 }
100 
101 static void
destroy_window(void)102 destroy_window (void)
103 {
104 	if (gtk_main_level () > 0) {
105 		xtm_settings_save_settings(settings);
106 		gtk_main_quit ();
107 	}
108 }
109 
110 static gboolean
delete_window(void)111 delete_window (void)
112 {
113 	if (!status_icon_get_visible ())
114 	{
115 		xtm_settings_save_settings(settings);
116 		gtk_main_quit ();
117 		return FALSE;
118 	}
119 	gtk_widget_hide (window);
120 	return TRUE;
121 }
122 
123 static gboolean
init_timeout(void)124 init_timeout (void)
125 {
126 	guint num_processes;
127 	gfloat cpu, memory_percent, swap_percent;
128 	guint64 swap_used, swap_free, swap_total, memory_used, memory_total;
129 	gchar *used, *total, tooltip[1024], memory_info[64], swap_info[64];
130 
131 	xtm_task_manager_get_system_info (task_manager, &num_processes, &cpu, &memory_used, &memory_total, &swap_used, &swap_total);
132 
133 	memory_percent = (memory_total != 0) ? ((memory_used * 100.0f) / (float)memory_total) : 0.0f;
134 	swap_percent = (swap_total != 0) ? ((swap_used * 100.0f) / (float)swap_total) : 0.0f;
135 
136 	used = g_format_size_full(memory_used, G_FORMAT_SIZE_IEC_UNITS);
137 	total = g_format_size_full(memory_total, G_FORMAT_SIZE_IEC_UNITS);
138 	g_snprintf (memory_info, sizeof(memory_info), "%.0f%% (%s / %s)", memory_percent, used, total);
139 	g_free(used);
140 	g_free(total);
141 
142 	used = g_format_size_full(swap_used, G_FORMAT_SIZE_IEC_UNITS);
143 	total = g_format_size_full(swap_total, G_FORMAT_SIZE_IEC_UNITS);
144 	g_snprintf (swap_info, sizeof(swap_info), "%.0f%% (%s / %s)", swap_percent, used, total);
145 	g_free(used);
146 	g_free(total);
147 
148 	xtm_process_window_set_system_info (XTM_PROCESS_WINDOW (window), num_processes, cpu, memory_percent, memory_info, swap_percent, swap_info);
149 
150 	xtm_task_manager_get_swap_usage (task_manager, &swap_free, &swap_total);
151 	xtm_process_window_show_swap_usage (XTM_PROCESS_WINDOW (window), (swap_total > 0));
152 
153 	if (status_icon_get_visible ())
154 	{
155 		g_snprintf (tooltip, sizeof(tooltip),
156 				_("<b>Processes:</b> %u\n"
157 				"<b>CPU:</b> %.0f%%\n"
158 				"<b>Memory:</b> %s\n"
159 				"<b>Swap:</b> %s"),
160 				num_processes, cpu, memory_info, swap_info);
161 		gtk_status_icon_set_tooltip_markup (GTK_STATUS_ICON (status_icon_or_null), tooltip);
162 	}
163 
164 	xtm_task_manager_update_model (task_manager);
165 
166 	if (timeout == 0)
167 	{
168 		guint refresh_rate;
169 		g_object_get (settings, "refresh-rate", &refresh_rate, NULL);
170 		timeout = g_timeout_add (refresh_rate, (GSourceFunc)init_timeout, NULL);
171 	}
172 
173 	return TRUE;
174 }
175 
176 static void
force_timeout_update(void)177 force_timeout_update (void)
178 {
179 	init_timeout ();
180 }
181 
182 static void
refresh_rate_changed(void)183 refresh_rate_changed (void)
184 {
185 	if (!g_source_remove (timeout))
186 	{
187 		g_critical ("Unable to remove source");
188 		return;
189 	}
190 	timeout = 0;
191 	init_timeout ();
192 }
193 
main(int argc,char * argv[])194 int main (int argc, char *argv[])
195 {
196 #if GLIB_CHECK_VERSION(2, 28, 0)
197 	GApplication *app;
198 	GError *error = NULL;
199 	GOptionContext *opt_context;
200 #endif
201 #ifdef ENABLE_NLS
202 	bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
203 	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
204 	textdomain (GETTEXT_PACKAGE);
205 #endif
206 
207 	gtk_init (&argc, &argv);
208 	g_set_application_name (_("Task Manager"));
209 
210 #if GLIB_CHECK_VERSION(2, 28, 0)
211 	opt_context = g_option_context_new ("");
212 	g_option_context_add_main_entries (opt_context, main_entries, NULL);
213 	g_option_context_add_group (opt_context, gtk_get_option_group (TRUE));
214 	if (!g_option_context_parse (opt_context, &argc, &argv, &error))
215 	{
216 		g_print ("Unable to parse arguments: %s\n", error->message);
217 		return 1;
218 	}
219 
220 	app = g_application_new ("xfce.taskmanager", 0);
221 	g_application_register (G_APPLICATION (app), NULL, &error);
222 	if (error != NULL)
223 	{
224 		g_warning ("Unable to register GApplication: %s", error->message);
225 		g_error_free (error);
226 		error = NULL;
227 	}
228 
229 	if (g_application_get_is_remote (G_APPLICATION (app)))
230 	{
231 		if (!start_hidden)
232 			g_application_activate (G_APPLICATION (app));
233 		g_object_unref (app);
234 		return 0;
235 	}
236 #endif
237 
238 	settings = xtm_settings_get_default ();
239 	show_hide_status_icon ();
240 
241 	window = xtm_process_window_new ();
242 
243 	if (!start_hidden)
244 		gtk_widget_show (window);
245 
246 #if GLIB_CHECK_VERSION(2, 28, 0)
247 	g_signal_connect_swapped (app, "activate", G_CALLBACK (xtm_process_window_show), window);
248 #endif
249 
250 	task_manager = xtm_task_manager_new (xtm_process_window_get_model (XTM_PROCESS_WINDOW (window)));
251 
252 	init_timeout ();
253 	g_signal_connect (settings, "notify::refresh-rate", G_CALLBACK (refresh_rate_changed), NULL);
254 	g_signal_connect_after (settings, "notify::more-precision", G_CALLBACK (force_timeout_update), NULL);
255 	g_signal_connect_after (settings, "notify::full-command-line", G_CALLBACK (force_timeout_update), NULL);
256 	g_signal_connect (settings, "notify::show-status-icon", G_CALLBACK (show_hide_status_icon), NULL);
257 
258 	g_signal_connect (window, "destroy", G_CALLBACK (destroy_window), NULL);
259 	g_signal_connect (window, "delete-event", G_CALLBACK (delete_window), NULL);
260 
261 	if (gtk_widget_get_visible (window) || status_icon_get_visible ())
262 		gtk_main ();
263 	else
264 		g_warning ("Nothing to do: activate hiding to the notification area when using --start-hidden");
265 
266 	if (timeout > 0)
267 		g_source_remove (timeout);
268 
269 	return 0;
270 }
271