I am using gtk-vnc-0.3.10 (on RHEL6), but also have used 0.5.2 (on RHEL7) with similar results. I've been having issues with properly destroying everything allocated to the VncDisplay.
The main driver for this is to have a vncviewer (started off with the gvncviewer.c example) which will automatically attempt reconnecting upon connection loss. While what I have is accomplishing the goal, every reconnect attempt leaks more and more memory (allocated during the vnc_display_open_host() call).
Valgrind seems to point to the GdkPixBuf area, but I would think that would be destroyed when I destroy the vnc object.
What I'm wondering is -- what's going wrong here (I don't see any obvious leaks on my part), or is there a better alternative to reconnecting that I could use instead?
Below is a stripped down (but compileable) version of gvncviewer I'm working with that expresses the problem. Compile, try a ./gvncviewer <random fake host> <random fake ip>,top -p $(pidof gvncviewer) and watch it grow.
#include "vncdisplay.h"
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include <glib-object.h>
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include <unistd.h>
GtkMessageDialog* not_avail = 0;
GtkDialogFlags not_avail_flags = GTK_DIALOG_MODAL;
GtkWidget *window = 0;
GOptionContext *context = 0;
GError *error = NULL;
char *display = 0;
GtkWidget *layout = 0;
char port[1024] = {0};
char hostname[1024] = {0};
static gchar **args = 0;
static GtkWidget *vnc = 0;
const char *help_msg = "Run 'gvncviewer --help' to see a full list of available command line options";
bool init();
static const GOptionEntry options [] =
{
{
G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_STRING_ARRAY, &args,
NULL, "[hostname][:display]" },
{ NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, 0 }
};
static void vnc_disconnected(GtkWidget *vncdisplay G_GNUC_UNUSED)
{
printf("disconnected! - %s - %s\n",hostname,port);
gtk_main_quit();
gtk_widget_destroy(GTK_WIDGET(vnc));
vnc=0;
gtk_widget_destroy(GTK_WIDGET(window));
window=0;
sleep(1);
init();
gtk_widget_hide_all(GTK_WIDGET(not_avail));
gtk_window_set_type_hint(GTK_WINDOW(not_avail),GDK_WINDOW_TYPE_HINT_SPLASHSCREEN);
gtk_window_set_position(GTK_WINDOW(not_avail),GTK_WIN_POS_CENTER_ALWAYS);
gtk_window_set_keep_below(GTK_WINDOW(not_avail), TRUE);
gtk_widget_show_all(GTK_WIDGET(not_avail));
gdk_window_lower(gtk_widget_get_window(GTK_WIDGET(not_avail)));
}
int main(int argc, char **argv)
{
/* Setup command line options */
context = g_option_context_new ("- Simple VNC Client");
g_option_context_add_main_entries (context, options, NULL);
g_option_context_add_group (context, gtk_get_option_group (TRUE));
g_option_context_add_group (context, vnc_display_get_option_group ());
g_option_context_parse (context, &argc, &argv, &error);
if (error) {
g_print ("%s\n%s\n",
error->message,
help_msg);
g_error_free (error);
return 1;
}
if (!args || (g_strv_length(args) != 1)) {
fprintf(stderr, "Usage: gvncviewer [hostname][:display]\n%s\n", help_msg);
return 1;
}
snprintf(hostname, sizeof(hostname), "%s", args[0]);
display = strchr(hostname, ':');
if (display) {
*display = 0;
snprintf(port, sizeof(port), "%d", 5900 + atoi(display + 1));
} else
snprintf(port, sizeof(port), "%d", 5900);
if (!*hostname)
snprintf(hostname, sizeof(hostname), "%s", "127.0.0.1");
init();
}
bool init() {
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_widget_hide_all(window);
layout = gtk_vbox_new(FALSE, 0);
gtk_window_set_resizable(GTK_WINDOW(window), TRUE);
gtk_window_set_keep_below(GTK_WINDOW(window), TRUE);
gtk_window_set_decorated(GTK_WINDOW(window),FALSE);
gtk_container_add(GTK_CONTAINER(window), layout);
vnc = vnc_display_new();
gtk_box_pack_start(GTK_BOX(layout), vnc, TRUE, TRUE, 0);
vnc_display_open_host(VNC_DISPLAY(vnc), hostname, port);
vnc_display_set_pointer_grab(VNC_DISPLAY(vnc), TRUE);
vnc_display_set_keyboard_grab(VNC_DISPLAY(vnc), TRUE);
gtk_widget_realize(vnc);
g_signal_connect(vnc, "vnc-disconnected",
G_CALLBACK(vnc_disconnected), NULL);
gtk_main();
return 0;
}