/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
Copyright (C) 2010-2015 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, see .
*/
#include
#include
#include "spice-common.h"
#include "spicy-connect.h"
typedef struct
{
gboolean connecting;
GMainLoop *loop;
SpiceSession *session;
} ConnectionInfo;
static struct {
const char *text;
const char *prop;
GtkWidget *entry;
} connect_entries[] = {
{ .text = "Hostname", .prop = "host" },
{ .text = "Port", .prop = "port" },
{ .text = "TLS Port", .prop = "tls-port" },
};
static gboolean can_connect(void)
{
if ((gtk_entry_get_text_length(GTK_ENTRY(connect_entries[0].entry)) > 0) &&
((gtk_entry_get_text_length(GTK_ENTRY(connect_entries[1].entry)) > 0) ||
(gtk_entry_get_text_length(GTK_ENTRY(connect_entries[2].entry)) > 0)))
return TRUE;
return FALSE;
}
static void set_connection_info(SpiceSession *session)
{
const gchar *txt;
int i;
for (i = 0; i < SPICE_N_ELEMENTS(connect_entries); i++) {
txt = gtk_entry_get_text(GTK_ENTRY(connect_entries[i].entry));
g_object_set(session, connect_entries[i].prop, txt, NULL);
}
}
static gboolean close_cb(gpointer data)
{
ConnectionInfo *info = data;
info->connecting = FALSE;
if (g_main_loop_is_running(info->loop))
g_main_loop_quit(info->loop);
return TRUE;
}
static void entry_changed_cb(GtkEditable* entry, gpointer data)
{
GtkButton *connect_button = data;
gtk_widget_set_sensitive(GTK_WIDGET(connect_button), can_connect());
}
static gboolean entry_focus_in_cb(GtkWidget *widget, GdkEvent *event, gpointer data)
{
GtkRecentChooser *recent = GTK_RECENT_CHOOSER(data);
gtk_recent_chooser_unselect_all(recent);
return TRUE;
}
static gboolean key_pressed_cb(GtkWidget *widget, GdkEvent *event, gpointer data)
{
gboolean tst;
if (event->type == GDK_KEY_PRESS) {
switch (event->key.keyval) {
case GDK_KEY_Escape:
g_signal_emit_by_name(GTK_WIDGET(data), "delete-event", NULL, &tst);
return TRUE;
default:
return FALSE;
}
}
return FALSE;
}
static void recent_selection_changed_dialog_cb(GtkRecentChooser *chooser, gpointer data)
{
GtkRecentInfo *info;
gchar *txt = NULL;
const gchar *uri;
SpiceSession *session = data;
int i;
info = gtk_recent_chooser_get_current_item(chooser);
if (info == NULL)
return;
uri = gtk_recent_info_get_uri(info);
g_return_if_fail(uri != NULL);
g_object_set(session, "uri", uri, NULL);
for (i = 0; i < SPICE_N_ELEMENTS(connect_entries); i++) {
g_object_get(session, connect_entries[i].prop, &txt, NULL);
gtk_entry_set_text(GTK_ENTRY(connect_entries[i].entry), txt ? txt : "");
g_free(txt);
}
gtk_recent_info_unref(info);
}
static void connect_cb(gpointer data)
{
ConnectionInfo *info = data;
if (can_connect())
{
info->connecting = TRUE;
set_connection_info(info->session);
if (g_main_loop_is_running(info->loop))
g_main_loop_quit(info->loop);
}
}
gboolean spicy_connect_dialog(SpiceSession *session)
{
GtkWidget *connect_button, *cancel_button, *label;
GtkBox *main_box, *recent_box, *button_box;
GtkWindow *window;
GtkGrid *grid;
int i;
ConnectionInfo info = {
FALSE,
NULL,
session
};
/* Create the widgets */
window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
gtk_window_set_title(window, "Connect to SPICE");
gtk_window_set_resizable(window, FALSE);
gtk_container_set_border_width(GTK_CONTAINER(window), 5);
main_box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, 0));
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(main_box));
grid = GTK_GRID(gtk_grid_new());
gtk_box_pack_start(main_box, GTK_WIDGET(grid), FALSE, TRUE, 0);
gtk_container_set_border_width(GTK_CONTAINER(grid), 5);
gtk_grid_set_row_spacing(grid, 5);
gtk_grid_set_column_spacing(grid, 5);
for (i = 0; i < SPICE_N_ELEMENTS(connect_entries); i++) {
gchar *txt;
label = gtk_label_new(connect_entries[i].text);
gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
gtk_grid_attach(grid, label, 0, i, 1, 1);
connect_entries[i].entry = GTK_WIDGET(gtk_entry_new());
gtk_grid_attach(grid, connect_entries[i].entry, 1, i, 1, 1);
g_object_get(session, connect_entries[i].prop, &txt, NULL);
SPICE_DEBUG("%s: #%i [%s]: \"%s\"",
__FUNCTION__, i, connect_entries[i].prop, txt);
if (txt) {
gtk_entry_set_text(GTK_ENTRY(connect_entries[i].entry), txt);
g_free(txt);
}
}
recent_box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_VERTICAL, 0));
gtk_box_pack_start(main_box, GTK_WIDGET(recent_box), TRUE, TRUE, 0);
gtk_container_set_border_width(GTK_CONTAINER(recent_box), 5);
label = gtk_label_new("Recent connections:");
gtk_box_pack_start(recent_box, label, FALSE, TRUE, 0);
gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
button_box = GTK_BOX(gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL));
gtk_button_box_set_layout(GTK_BUTTON_BOX(button_box), GTK_BUTTONBOX_END);
gtk_box_set_spacing(button_box, 5);
gtk_container_set_border_width(GTK_CONTAINER(button_box), 5);
connect_button = gtk_button_new_with_label("Connect");
cancel_button = gtk_button_new_with_label("Cancel");
gtk_box_pack_start(button_box, cancel_button, FALSE, TRUE, 0);
gtk_box_pack_start(button_box, connect_button, FALSE, TRUE, 1);
gtk_box_pack_start(main_box, GTK_WIDGET(button_box), FALSE, TRUE, 0);
gtk_widget_set_sensitive(GTK_WIDGET(connect_button), can_connect());
g_signal_connect(window, "key-press-event",
G_CALLBACK(key_pressed_cb), window);
g_signal_connect_swapped(window, "delete-event",
G_CALLBACK(close_cb), &info);
g_signal_connect_swapped(connect_button, "clicked",
G_CALLBACK(connect_cb), &info);
g_signal_connect_swapped(cancel_button, "clicked",
G_CALLBACK(close_cb), &info);
GtkRecentFilter *rfilter;
GtkWidget *recent;
recent = GTK_WIDGET(gtk_recent_chooser_widget_new());
gtk_recent_chooser_set_show_icons(GTK_RECENT_CHOOSER(recent), FALSE);
gtk_box_pack_start(recent_box, recent, TRUE, TRUE, 0);
rfilter = gtk_recent_filter_new();
gtk_recent_filter_add_mime_type(rfilter, "application/x-spice");
gtk_recent_chooser_set_filter(GTK_RECENT_CHOOSER(recent), rfilter);
gtk_recent_chooser_set_local_only(GTK_RECENT_CHOOSER(recent), FALSE);
g_signal_connect(recent, "selection-changed",
G_CALLBACK(recent_selection_changed_dialog_cb), session);
g_signal_connect_swapped(recent, "item-activated",
G_CALLBACK(connect_cb), &info);
for (i = 0; i < SPICE_N_ELEMENTS(connect_entries); i++) {
g_signal_connect_swapped(connect_entries[i].entry, "activate",
G_CALLBACK(connect_cb), &info);
g_signal_connect(connect_entries[i].entry, "changed",
G_CALLBACK(entry_changed_cb), connect_button);
g_signal_connect(connect_entries[i].entry, "focus-in-event",
G_CALLBACK(entry_focus_in_cb), recent);
}
/* show and wait for response */
gtk_widget_show_all(GTK_WIDGET(window));
info.loop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(info.loop);
gtk_widget_destroy(GTK_WIDGET(window));
return info.connecting;
}