1 /* gmpc-serverstats (GMPC plugin)
2  * Copyright (C) 2006-2011 Qball Cow <qball@gmpclient.org>
3  * Project homepage: http://gmpclient.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  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14 
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 
20 #include <gtk/gtk.h>
21 #include <gdk/gdkkeysyms.h>
22 #include <config.h>
23 #include "main.h"
24 #include "plugin.h"
25 #include "playlist3-messages.h"
26 #include "playlist3.h"
27 #include "misc.h"
28 
29 gmpcPlugin statistics_plugin;
30 enum
31 {
32 	SERVERSTATS_MPD_VERSION,
33 	SERVERSTATS_MPD_UPTIME,
34 	SERVERSTATS_MPD_PLAYTIME,
35 	SERVERSTATS_MPD_DB_PLAYTIME,
36 	SERVERSTATS_MPD_DB_ARTISTS,
37 	SERVERSTATS_MPD_DB_ALBUMS,
38 	SERVERSTATS_MPD_DB_SONGS,
39 	SERVERSTATS_MPD_URLHANDLERS,
40 	SERVERSTATS_MPD_TAG_TYPES,
41 	SERVERSTATS_NUM_FIELDS
42 };
43 
44 static GtkWidget *serverstats_sw = NULL, *serverstats_tree = NULL;
45 static GtkWidget *serverstats_labels[SERVERSTATS_NUM_FIELDS];
46 static gboolean cancel_query = FALSE;
47 
48 /**
49  * Playlist browser functions
50  */
51 
serverstats_clear(void)52 static void serverstats_clear(void)
53 {
54 	int i;
55 	for (i = 0; i < SERVERSTATS_NUM_FIELDS; i++)
56 	{
57 		gtk_label_set_text(GTK_LABEL(serverstats_labels[i]), "");
58 	}
59 
60 }
61 
serverstats_update(void)62 static void serverstats_update(void)
63 {
64 	gchar **handlers = NULL;
65 	gchar *value = NULL;
66 
67 	serverstats_clear();
68 	if (!mpd_check_connected(connection))
69 		return;
70 	mpd_stats_update(connection);
71 	/** Version */
72 	value = mpd_server_get_version(connection);
73 	gtk_label_set_text(GTK_LABEL(serverstats_labels[SERVERSTATS_MPD_VERSION]), value);
74 	free(value);
75 	/** Uptime  */
76 	value = format_time_real(mpd_stats_get_uptime(connection), "");
77 	gtk_label_set_text(GTK_LABEL(serverstats_labels[SERVERSTATS_MPD_UPTIME]), value);
78 	g_free(value);
79 	/** Playtime*/
80 	value = format_time_real(mpd_stats_get_playtime(connection), "");
81 	gtk_label_set_text(GTK_LABEL(serverstats_labels[SERVERSTATS_MPD_PLAYTIME]), value);
82 	g_free(value);
83 	/** DB Playtime*/
84 	value = format_time_real(mpd_stats_get_db_playtime(connection), "");
85 	gtk_label_set_text(GTK_LABEL(serverstats_labels[SERVERSTATS_MPD_DB_PLAYTIME]), value);
86 	g_free(value);
87 	/** DB ARTIST*/
88 	value = g_strdup_printf("%i", mpd_stats_get_total_artists(connection));
89 	gtk_label_set_text(GTK_LABEL(serverstats_labels[SERVERSTATS_MPD_DB_ARTISTS]), value);
90 	g_free(value);
91 	/** DB ALBUMS*/
92 	value = g_strdup_printf("%i", mpd_stats_get_total_albums(connection));
93 	gtk_label_set_text(GTK_LABEL(serverstats_labels[SERVERSTATS_MPD_DB_ALBUMS]), value);
94 	g_free(value);
95 	/** DB SONGS*/
96 	value = g_strdup_printf("%i", mpd_stats_get_total_songs(connection));
97 	gtk_label_set_text(GTK_LABEL(serverstats_labels[SERVERSTATS_MPD_DB_SONGS]), value);
98 	g_free(value);
99 	/** URL_HANDLERS*/
100 	handlers = mpd_server_get_url_handlers(connection);
101 	if (handlers)
102 	{
103 		value = g_strjoinv(",", handlers);
104 		g_strfreev(handlers);
105 		handlers = NULL;
106 	} else
107 		value = g_strdup("N/A");
108 	gtk_label_set_text(GTK_LABEL(serverstats_labels[SERVERSTATS_MPD_URLHANDLERS]), value);
109 	g_free(value);
110 
111 	if (mpd_server_check_version(connection, 0, 13, 0))
112 		handlers = mpd_server_get_tag_types(connection);
113 	if (handlers)
114 	{
115 		value = g_strjoinv(", ", handlers);
116 		g_strfreev(handlers);
117 		handlers = NULL;
118 	} else
119 		value = g_strdup("N/A");
120 	gtk_label_set_text(GTK_LABEL(serverstats_labels[SERVERSTATS_MPD_TAG_TYPES]), value);
121 	g_free(value);
122 
123 }
124 
125 typedef struct _ss_str
126 {
127 	int total;
128 	int tag;
129 	int hits;
130 	MpdData *data;
131 	GtkTreeModel *model;
132 	GtkWidget *box, *pb;
133 	long unsigned max_i;
134 } ss_str;
135 
serverstats_idle_handler(ss_str * s)136 static gboolean serverstats_idle_handler(ss_str * s)
137 {
138 	GtkTreeIter iter;
139 	MpdDBStats *stats = NULL;
140 	if (s->data == NULL || !mpd_check_connected(connection) || cancel_query)
141 	{
142 
143 		if (gtk_tree_model_get_iter_first(s->model, &iter))
144 		{
145 			do
146 			{
147 				guint d;
148 				gulong i;
149 				gchar *value = NULL;
150 				gtk_tree_model_get(s->model, &iter, 0, &i, -1);
151 				d = (guint) 100 *(i / (double)s->max_i);
152 				value = format_time_real(i, "");
153 				gtk_list_store_set(GTK_LIST_STORE(s->model), &iter, 2, d, 3, value, -1);
154 				g_free(value);
155 			} while (gtk_tree_model_iter_next(s->model, &iter));
156 		}
157 
158 		if (s->data)
159 			mpd_data_free(s->data);
160 		gtk_tree_view_set_model(GTK_TREE_VIEW(serverstats_tree), s->model);
161 		gtk_tree_view_set_search_column(GTK_TREE_VIEW(serverstats_tree), 1);
162 		gtk_widget_set_sensitive(GTK_WIDGET(s->box), TRUE);
163 		gtk_widget_hide(gtk_widget_get_parent(s->pb));
164 
165 		if (cancel_query)
166 			gtk_list_store_clear(GTK_LIST_STORE(s->model));
167 		g_free(s);
168 		cancel_query = FALSE;
169 		return FALSE;
170 	}
171 	mpd_database_search_stats_start(connection);
172 	mpd_database_search_add_constraint(connection, s->tag, s->data->tag);
173 
174 	stats = mpd_database_search_stats_commit(connection);
175 	if (stats)
176 	{
177 		gtk_list_store_prepend(GTK_LIST_STORE(s->model), &iter);
178 		gtk_list_store_set(GTK_LIST_STORE(s->model), &iter, 0, (unsigned long)(stats->playTime), 1, s->data->tag, -1);
179 		s->max_i = MAX(s->max_i, stats->playTime);
180 
181 		mpd_database_search_free_stats(stats);
182 	}
183 	/* limit the amount of updating to 0.2 % */
184 	if ((int)((1000 * s->hits) / s->total) % 5 == 0)
185 	{
186 		gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(s->pb), s->hits / (double)s->total);
187 	}
188 	s->hits++;
189 	s->data = mpd_data_get_next(s->data);
190 	return TRUE;
191 }
192 
serverstats_combo_changed(GtkComboBox * box,GtkWidget * pb)193 static void serverstats_combo_changed(GtkComboBox * box, GtkWidget * pb)
194 {
195 	ss_str *s;
196 	int hits, total;
197 	gulong max_i;
198 	MpdData *node, *data;
199 	GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(serverstats_tree));
200 	int tag = gtk_combo_box_get_active(box);
201 
202 	if (!mpd_check_connected(connection))
203 		return;
204 	if (!mpd_server_check_version(connection, 0, 13, 0))
205 	{
206 		playlist3_show_error_message("This feature is not supported in mpd older then version 0.13.0.", ERROR_WARNING);
207 		return;
208 	}
209 	/* reset the cancel flag */
210 	cancel_query = FALSE;
211 	/* show progress bar */
212 
213 	gtk_widget_show_all(gtk_widget_get_parent(pb));
214 
215 	/** make the combo box insensitive and remove the model from the treeview */
216 	gtk_tree_view_set_model(GTK_TREE_VIEW(serverstats_tree), NULL);
217 	gtk_widget_set_sensitive(GTK_WIDGET(box), FALSE);
218 
219 	gtk_list_store_clear(GTK_LIST_STORE(model));
220 	mpd_database_search_field_start(connection, tag);
221 	data = mpd_database_search_commit(connection);
222 	max_i = 0;
223 
224 	hits = 0;
225 	total = 0;
226 	for (node = mpd_data_get_first(data); node != NULL; node = (MpdData *) mpd_data_get_next_real(node, FALSE))
227 		total++;
228 	s = g_malloc0(sizeof(*s));
229 	s->total = total;
230 	s->model = model;
231 	s->data = data;
232 	s->hits = 0;
233 	s->tag = tag;
234 	s->pb = pb;
235 	s->box = GTK_WIDGET(box);
236 	g_idle_add((GSourceFunc) serverstats_idle_handler, s);
237 
238 }
239 
serverstats_header_style_changed(GtkWidget * vbox,GtkStyle * style,GtkWidget * vp)240 static void serverstats_header_style_changed(GtkWidget * vbox, GtkStyle * style, GtkWidget * vp)
241 {
242 	gtk_widget_modify_bg(vp, GTK_STATE_NORMAL, &(GTK_WIDGET(vbox)->style->base[GTK_STATE_NORMAL]));
243 }
244 
cancel_clicked(GtkWidget * cancel,gpointer data)245 static void cancel_clicked(GtkWidget * cancel, gpointer data)
246 {
247 	cancel_query = TRUE;
248 }
249 
serverstats_add_entry(GtkWidget * table,int i,const char * name,int stats)250 static void serverstats_add_entry(GtkWidget * table, int i, const char *name, int stats)
251 {
252 	char *markup;
253 	GtkWidget *label;
254 	/** Mpd Uptime */
255 	label = gtk_label_new("");
256 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.0);
257 	gtk_misc_set_padding(GTK_MISC(label), 12, 0);
258 	markup = g_markup_printf_escaped("<b>%s:</b>", name);
259 	gtk_label_set_markup(GTK_LABEL(label), markup);
260 	g_free(markup);
261 	gtk_table_attach(GTK_TABLE(table), label, 0, 1, i, i + 1, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
262 	label = serverstats_labels[stats] = gtk_label_new("");
263 	gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
264 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
265 	gtk_table_attach(GTK_TABLE(table), label, 1, 2, i, i + 1, GTK_EXPAND | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
266 }
267 
serverstats_init(void)268 static void serverstats_init(void)
269 {
270 	/** Get an allready exposed widgets to grab theme colors from. */
271 	GtkWidget *colw = (GtkWidget *) playlist3_get_category_tree_view();
272 	GtkWidget *label = NULL;
273 	GtkWidget *table = NULL;
274 	GtkWidget *hbox = NULL;
275 	GtkWidget *event = NULL;
276 	GtkWidget *serverstats_vbox = gtk_vbox_new(FALSE, 0);
277 	GtkWidget *serverstats_event;
278 	gchar *markup = NULL;
279 	int i = 0;
280 
281 	serverstats_sw = gtk_scrolled_window_new(NULL, NULL);
282 	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(serverstats_sw), GTK_SHADOW_IN);
283 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(serverstats_sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
284 
285 	serverstats_event = gtk_event_box_new();
286 	gtk_event_box_set_visible_window(GTK_EVENT_BOX(serverstats_event), TRUE);
287 	gtk_container_add(GTK_CONTAINER(serverstats_event), serverstats_vbox);
288 
289 	/* wrap in event box to set bg color */
290 	event = gtk_event_box_new();
291 	gtk_widget_set_app_paintable(event, TRUE);
292 	gtk_event_box_set_visible_window(GTK_EVENT_BOX(event), TRUE);
293 	gtk_widget_set_state(GTK_WIDGET(event), GTK_STATE_SELECTED);
294 	g_signal_connect(G_OBJECT(event), "expose-event", G_CALLBACK(misc_header_expose_event), NULL);
295 
296 	gtk_widget_modify_bg(serverstats_event, GTK_STATE_NORMAL, &(colw->style->base[GTK_STATE_NORMAL]));
297 	g_signal_connect(G_OBJECT(serverstats_vbox), "style-set", G_CALLBACK(serverstats_header_style_changed),
298 					 serverstats_event);
299 
300 	/* set label and padding */
301 	hbox = gtk_hbox_new(FALSE, 6);
302 	label = gtk_image_new_from_icon_name("mpd", GTK_ICON_SIZE_DND);
303 	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0);
304 	label = gtk_label_new("");
305 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
306 	markup = g_markup_printf_escaped("<span size='xx-large' weight='bold'>%s</span>", _("Server Information"));
307 	gtk_label_set_markup(GTK_LABEL(label), markup);
308 	g_free(markup);
309 	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0);
310 	gtk_container_add(GTK_CONTAINER(event), hbox);
311 
312 	gtk_container_set_border_width(GTK_CONTAINER(hbox), 6);
313 	gtk_box_pack_start(GTK_BOX(serverstats_vbox), event, FALSE, TRUE, 0);
314 	gtk_widget_show_all(event);
315 
316 	label = gtk_hseparator_new();
317 	gtk_box_pack_start(GTK_BOX(serverstats_vbox), label, FALSE, TRUE, 0);
318 	gtk_widget_show(label);
319 	/**
320      * Data list
321      */
322 	table = gtk_table_new(SERVERSTATS_NUM_FIELDS + 2, 2, FALSE);
323 	gtk_table_set_col_spacings(GTK_TABLE(table), 6);
324 	gtk_table_set_row_spacings(GTK_TABLE(table), 6);
325 	gtk_container_set_border_width(GTK_CONTAINER(table), 12);
326 
327 	/** Database */
328 	label = gtk_label_new("");
329 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
330 	markup = g_markup_printf_escaped("<span size='x-large' weight='bold'>%s</span>", _("Server"));
331 	gtk_label_set_markup(GTK_LABEL(label), markup);
332 	g_free(markup);
333 	gtk_table_attach(GTK_TABLE(table), label, 0, 2, 0, 1, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
334 
335 	i = 1;
336 	/** Mpd version */
337 	serverstats_add_entry(table, i++, _("Version"), SERVERSTATS_MPD_VERSION);
338 
339 	serverstats_add_entry(table, i++, _("Uptime"), SERVERSTATS_MPD_UPTIME);
340 	serverstats_add_entry(table, i++, _("Time Playing"), SERVERSTATS_MPD_PLAYTIME);
341 
342 	/** Database */
343 	label = gtk_label_new("");
344 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
345 
346 	markup = g_markup_printf_escaped("<span size='x-large' weight='bold'>%s</span>", _("Database"));
347 	gtk_label_set_markup(GTK_LABEL(label), markup);
348 	g_free(markup);
349 	gtk_table_attach(GTK_TABLE(table), label, 0, 2, i, i + 1, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
350 	i++;
351 
352 	/** Mpd Playtime */
353 	serverstats_add_entry(table, i++, _("Total Playtime"), SERVERSTATS_MPD_DB_PLAYTIME);
354 	/** Mpd Artists*/
355 	serverstats_add_entry(table, i++, _("Number of artists"), SERVERSTATS_MPD_DB_ARTISTS);
356 	/** Mpd Albums */
357 	serverstats_add_entry(table, i++, _("Number of albums"), SERVERSTATS_MPD_DB_ALBUMS);
358 	/** Mpd Songs */
359 	serverstats_add_entry(table, i++, _("Number of songs"), SERVERSTATS_MPD_DB_SONGS);
360 	/** Mpd Songs */
361 	serverstats_add_entry(table, i++, _("URL Handlers"), SERVERSTATS_MPD_URLHANDLERS);
362 	/** Mpd Songs */
363 	serverstats_add_entry(table, i++, _("Tag Types"), SERVERSTATS_MPD_TAG_TYPES);
364 	/** Stats */
365 	label = gtk_label_new("");
366 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
367 
368 	markup = g_markup_printf_escaped("<span size='x-large' weight='bold'>%s</span>", _("Tag statistics"));
369 	gtk_label_set_markup(GTK_LABEL(label), markup);
370 	g_free(markup);
371 	gtk_table_attach(GTK_TABLE(table), label, 0, 2, i, i + 1, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
372 	i++;
373 	gtk_widget_show_all(table);
374 
375 	/**
376      * Stats treeview
377      */
378 	{
379 		GtkWidget *combo = NULL;
380 		GtkWidget *sw = NULL, *cancel;
381 		GtkListStore *store;
382 		GtkCellRenderer *renderer;
383 		GtkWidget *pb = gtk_progress_bar_new();
384 		combo = gtk_combo_box_new_text();
385 		for (i = 0; i < MPD_TAG_NUM_OF_ITEM_TYPES - 1; i++)
386 		{
387 			if (mpd_server_tag_supported(connection, i))
388 			{
389 				gtk_combo_box_append_text(GTK_COMBO_BOX(combo), mpdTagItemKeys[i]);
390 			}
391 		}
392 
393 		gtk_table_attach(GTK_TABLE(table), combo, 0, 2, 12, 13, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
394 		gtk_widget_show(combo);
395 
396 		hbox = gtk_hbox_new(FALSE, 6);
397 		cancel = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
398 		g_signal_connect(G_OBJECT(cancel), "clicked", G_CALLBACK(cancel_clicked), NULL);
399 		gtk_box_pack_start(GTK_BOX(hbox), pb, TRUE, TRUE, 0);
400 		gtk_box_pack_start(GTK_BOX(hbox), cancel, FALSE, TRUE, 0);
401 
402 		gtk_table_attach(GTK_TABLE(table), hbox, 0, 2, 13, 14, GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
403 		g_signal_connect(G_OBJECT(combo), "changed", G_CALLBACK(serverstats_combo_changed), pb);
404 
405 		sw = gtk_scrolled_window_new(NULL, NULL);
406 		gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
407 		gtk_container_set_border_width(GTK_CONTAINER(sw), 6);
408 
409 		store = gtk_list_store_new(4, G_TYPE_ULONG, G_TYPE_STRING, G_TYPE_ULONG, G_TYPE_STRING);
410 		gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store), 0, GTK_SORT_DESCENDING);
411 		serverstats_tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
412 		gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(serverstats_tree), FALSE);
413 		gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(serverstats_tree), TRUE);
414 		renderer = gtk_cell_renderer_text_new();
415 		g_object_set(G_OBJECT(renderer), "ellipsize", PANGO_ELLIPSIZE_END, "ellipsize-set", TRUE, "width-chars", 30,
416 					 NULL);
417 		gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(serverstats_tree), -1, "", renderer, "text", 1, NULL);
418 		renderer = gtk_cell_renderer_progress_new();
419 		gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(serverstats_tree),
420 													-1, "", renderer, "value", 2, "text", 3, NULL);
421 
422 		gtk_tree_view_set_search_column(GTK_TREE_VIEW(serverstats_tree), 1);
423 
424 		gtk_container_add(GTK_CONTAINER(sw), serverstats_tree);
425 
426 		gtk_table_attach(GTK_TABLE(table), sw, 0, 2, 14, 15, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
427 		gtk_widget_show_all(sw);
428 	}
429 	/**
430      * Add table
431      */
432 	gtk_box_pack_start(GTK_BOX(serverstats_vbox), table, TRUE, TRUE, 0);
433 	/* maintain my own reference to the widget, so it won't get destroyed removing
434 	 * from view
435 	 */
436 	gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(serverstats_sw), serverstats_event);
437 	gtk_widget_show(serverstats_vbox);
438 	gtk_widget_show(serverstats_event);
439 	gtk_widget_show(serverstats_sw);
440 	g_object_ref_sink(serverstats_sw);
441 }
442 
443 static guint timeout_source = 0;
444 
serverstats_selected(GtkWidget * container)445 static void serverstats_selected(GtkWidget * container)
446 {
447 	if (serverstats_sw == NULL)
448 	{
449 		serverstats_init();
450 	}
451 	serverstats_update();
452 	gtk_container_add(GTK_CONTAINER(container), serverstats_sw);
453 	gtk_widget_show(serverstats_sw);
454 	if (timeout_source)
455 		g_source_remove(timeout_source);
456 	timeout_source = g_timeout_add_seconds(5, (GSourceFunc) serverstats_update, NULL);
457 }
458 
serverstats_unselected(GtkWidget * container)459 static void serverstats_unselected(GtkWidget * container)
460 {
461 	if (timeout_source)
462 		g_source_remove(timeout_source);
463 	timeout_source = 0;
464 	gtk_container_remove(GTK_CONTAINER(container), serverstats_sw);
465 }
466 
467 /**
468  * public function
469  */
serverinformation_popup_close(GtkWidget * dialog,gint response_id,gpointer data)470 static void serverinformation_popup_close(GtkWidget * dialog, gint response_id, gpointer data)
471 {
472 	int width, height;
473 	/* Save windows size */
474 	gtk_window_get_size(GTK_WINDOW(dialog), &width, &height);
475 	cfg_set_single_value_as_int(config, "serverstats", "dialog-width", width);
476 	cfg_set_single_value_as_int(config, "serverstats", "dialog-height", height);
477 
478 	/* Remove info window, and keep it */
479 	serverstats_unselected(GTK_DIALOG(dialog)->vbox);
480 
481 	/* destroy dialog */
482 	gtk_widget_destroy(dialog);
483 
484 }
485 
serverstats_connection_changed(MpdObj * mi,int connect,void * usedata)486 static void serverstats_connection_changed(MpdObj * mi, int connect, void *usedata)
487 {
488 	if (!connect && serverstats_tree)
489 	{
490 		GtkWidget *dialog = gtk_widget_get_parent(serverstats_sw);
491 		if (dialog)
492 			gtk_dialog_response(GTK_DIALOG(gtk_widget_get_toplevel(dialog)), 0);
493 		if (serverstats_sw)
494 		{
495 			gtk_widget_destroy(serverstats_sw);
496 			serverstats_sw = NULL;
497 			serverstats_tree = NULL;
498 		}
499 	}
500 }
501 
serverinformation_show_popup(void)502 void serverinformation_show_popup(void)
503 {
504 	GtkWidget *dialog = NULL;
505 	if (serverstats_sw)
506 	{
507 		GtkWidget *win = gtk_widget_get_parent(serverstats_sw);
508 		if (win)
509 		{
510 			gtk_window_present(GTK_WINDOW(win));
511 			return;
512 		}
513 	}
514 
515 	dialog = gtk_dialog_new_with_buttons(_("Server Information"),
516 										 GTK_WINDOW(playlist3_get_window()),
517 										 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
518 										 GTK_STOCK_CLOSE, GTK_RESPONSE_OK, NULL);
519 	/* Add info window */
520 	serverstats_selected(GTK_DIALOG(dialog)->vbox);
521 	/* Restore size */
522 	gtk_window_resize(GTK_WINDOW(dialog),
523 					  cfg_get_single_value_as_int_with_default(config, "serverstats", "dialog-width", 400),
524 					  cfg_get_single_value_as_int_with_default(config, "serverstats", "dialog-height", 400));
525 	/* handle close */
526 	g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(serverinformation_popup_close), NULL);
527 	gtk_widget_show(dialog);
528 
529 }
530 
serverstats_destroy(void)531 static void serverstats_destroy(void)
532 {
533 	serverstats_connection_changed(connection, 0, NULL);
534 }
535 
536 /**
537  * Define the plugin structure
538  */
539 gmpcPlugin statistics_plugin = {
540 	/* name */
541 	.name = N_("Server Information"),
542 	/* version */
543 	.version = {0, 1, 2},
544 	.destroy = serverstats_destroy,
545 	/* type */
546 	.plugin_type = GMPC_INTERNALL,
547 	/** Connection changed */
548 	.mpd_connection_changed = serverstats_connection_changed
549 };
550