[Spice-devel] [spice-gtk PATCH 1/3 v2] spicy-connect: Connect dialog changed to window
Lukas Venhoda
lvenhoda at redhat.com
Tue Jun 9 07:59:32 PDT 2015
Connect dialog in spicy had no transinient parent.
It didn't make much sense for it to be a dialog.
Changed the connect dialog to a window.
Moved the dialog code to its own module.
Changed response ID from ambiguous -1 and 0 to GTK_RESPONSE_ACCEPT
and GTK_RESPONSE_REJECT.
Improved UX:
- ESC to close, ENTER to connect.
- Address and port are now required to connect.
- Focusing in entries will now unselect recent connection.
- If you rewrite something in entries, you can now reselect
connection in the recent chooser.
---
Changes since v1:
- Rebased for latest directory structure
- Moved UI back from XML to code
- Building from XML would require large rewrite of Makefile
- Rest of SPICY is written in code, so making XML for 1 dialog is weird
- Changed response IDs from magical numbers to GTK enums
- Improved UX
---
src/spicy-connect.c | 293 ++++++++++++++++++++++++++++++++++++++++++++++++++++
src/spicy-connect.h | 26 +++++
2 files changed, 319 insertions(+)
create mode 100644 src/spicy-connect.c
create mode 100644 src/spicy-connect.h
diff --git a/src/spicy-connect.c b/src/spicy-connect.c
new file mode 100644
index 0000000..3024b84
--- /dev/null
+++ b/src/spicy-connect.c
@@ -0,0 +1,293 @@
+/* -*- 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+#include <gdk/gdkkeysyms.h>
+#include "spice-common.h"
+#include "spicy-connect.h"
+
+typedef struct
+{
+ GtkResponseType response_id;
+ GMainLoop *loop;
+ SpiceSession *session;
+} ConnectionInfo;
+
+static struct {
+ const char *text;
+ const char *prop;
+ GtkWidget *entry;
+} connect_entries[] = {
+ { .text = N_("Hostname"), .prop = "host" },
+ { .text = N_("Port"), .prop = "port" },
+ { .text = N_("TLS Port"), .prop = "tls-port" },
+};
+
+static void
+shutdown_loop(GMainLoop *loop)
+{
+ if (g_main_loop_is_running(loop))
+ g_main_loop_quit(loop);
+}
+
+static void
+set_connection_info(SpiceSession *session)
+{
+ const gchar *txt;
+ txt = gtk_entry_get_text(GTK_ENTRY(connect_entries[0].entry));
+ g_object_set(session, "host", txt, NULL);
+
+ txt = gtk_entry_get_text(GTK_ENTRY(connect_entries[1].entry));
+ g_object_set(session, "port", txt, NULL);
+
+ txt = gtk_entry_get_text(GTK_ENTRY(connect_entries[2].entry));
+ g_object_set(session, "tls-port", txt, NULL);
+}
+
+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))
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+window_deleted_cb(GtkWindow *window, GdkEventAny *event, gpointer data)
+{
+ ConnectionInfo *ci = data;
+ ci->response_id = GTK_RESPONSE_REJECT;
+ shutdown_loop(ci->loop);
+ return TRUE;
+}
+
+static void
+cancel_button_clicked_cb(GtkButton *button, gpointer data)
+{
+ ConnectionInfo *ci = data;
+ ci->response_id = GTK_RESPONSE_REJECT;
+ shutdown_loop(ci->loop);
+}
+
+static void
+connect_button_clicked_cb(GtkButton *button, gpointer data)
+{
+ ConnectionInfo *ci = data;
+ if (can_connect())
+ {
+ ci->response_id = GTK_RESPONSE_ACCEPT;
+ set_connection_info(ci->session);
+ shutdown_loop(ci->loop);
+ }
+}
+
+static void
+entry_activated_cb(GtkEntry *entry, gpointer data)
+{
+ ConnectionInfo *ci = data;
+
+ if (can_connect())
+ {
+ ci->response_id = GTK_RESPONSE_ACCEPT;
+ set_connection_info(ci->session);
+ shutdown_loop(ci->loop);
+ }
+}
+
+static gboolean
+entry_focus_in_cb(GtkWidget *widget, GdkEvent *event, gpointer data)
+{
+ GtkRecentChooser *recent = data;
+ gtk_recent_chooser_unselect_all(recent);
+ return TRUE;
+}
+
+static void
+recent_item_activated_dialog_cb(GtkRecentChooser *chooser, gpointer data)
+{
+ ConnectionInfo *ci = data;
+
+ if (can_connect())
+ {
+ ci->response_id = GTK_RESPONSE_ACCEPT;
+ set_connection_info(ci->session);
+ shutdown_loop(ci->loop);
+ }
+}
+
+static void
+recent_selection_changed_dialog_cb(GtkRecentChooser *chooser, gpointer data)
+{
+ GtkRecentInfo *info;
+ gchar *txt = NULL;
+ const gchar *uri;
+ SpiceSession *session = data;
+
+ 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);
+
+ g_object_get(session, "host", &txt, NULL);
+ gtk_entry_set_text(GTK_ENTRY(connect_entries[0].entry), txt ? txt : "");
+ g_free(txt);
+
+ g_object_get(session, "port", &txt, NULL);
+ gtk_entry_set_text(GTK_ENTRY(connect_entries[1].entry), txt ? txt : "");
+ g_free(txt);
+
+ g_object_get(session, "tls-port", &txt, NULL);
+ gtk_entry_set_text(GTK_ENTRY(connect_entries[2].entry), txt ? txt : "");
+ g_free(txt);
+
+ gtk_recent_info_unref(info);
+}
+
+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;
+}
+
+int
+connect_dialog(SpiceSession *session)
+{
+ GtkWidget *connect_button, *cancel_button, *label;
+ GtkBox *main_box, *recent_box, *button_box;
+ GtkRecentChooser *recent;
+ GtkRecentFilter *rfilter;
+ GtkWindow *window;
+ GtkTable *table;
+ int i;
+
+ ConnectionInfo ci = {
+ GTK_RESPONSE_NONE,
+ NULL,
+ session,
+ NULL,
+ NULL,
+ NULL
+ };
+
+ 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_vbox_new(FALSE, 0));
+ gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(main_box));
+
+ table = GTK_TABLE(gtk_table_new(3, 2, 0));
+ gtk_box_pack_start(main_box, GTK_WIDGET(table), FALSE, TRUE, 0);
+ gtk_container_set_border_width(GTK_CONTAINER(table), 5);
+ gtk_table_set_row_spacings(table, 5);
+ gtk_table_set_col_spacings(table, 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_table_attach_defaults(table, label, 0, 1, i, i+1);
+
+ connect_entries[i].entry = GTK_WIDGET(gtk_entry_new());
+ gtk_table_attach_defaults(table, connect_entries[i].entry, 1, 2, i, i+1);
+
+ g_object_get(session, connect_entries[i].prop, &txt, NULL);
+ if (txt) {
+ gtk_entry_set_text(GTK_ENTRY(connect_entries[i].entry), txt);
+ g_free(txt);
+ }
+ }
+
+ recent_box = GTK_BOX(gtk_vbox_new(FALSE, 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);
+
+ recent = GTK_RECENT_CHOOSER(gtk_recent_chooser_widget_new());
+ gtk_recent_chooser_set_show_icons(recent, FALSE);
+ gtk_box_pack_start(recent_box, GTK_WIDGET(recent), TRUE, TRUE, 0);
+
+ rfilter = gtk_recent_filter_new();
+ gtk_recent_filter_add_mime_type(rfilter, "application/x-spice");
+ gtk_recent_chooser_set_filter(recent, rfilter);
+ gtk_recent_chooser_set_local_only(recent, FALSE);
+
+ button_box = GTK_BOX(gtk_hbutton_box_new());
+ 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);
+
+ g_signal_connect(window, "delete-event",
+ G_CALLBACK(window_deleted_cb), &ci);
+ g_signal_connect(window, "key-press-event",
+ G_CALLBACK(key_pressed_cb), window);
+ g_signal_connect(connect_button, "clicked",
+ G_CALLBACK(connect_button_clicked_cb), &ci);
+ g_signal_connect(cancel_button, "clicked",
+ G_CALLBACK(cancel_button_clicked_cb), &ci);
+
+ for (i = 0; i < SPICE_N_ELEMENTS(connect_entries); i++) {
+ g_signal_connect(connect_entries[i].entry, "activate",
+ G_CALLBACK(entry_activated_cb), &ci);
+ g_signal_connect(connect_entries[i].entry, "focus-in-event",
+ G_CALLBACK(entry_focus_in_cb), recent);
+ }
+
+ g_signal_connect(recent, "selection-changed",
+ G_CALLBACK(recent_selection_changed_dialog_cb), session);
+ g_signal_connect(recent, "item-activated",
+ G_CALLBACK(recent_item_activated_dialog_cb), &ci);
+
+ gtk_widget_show_all(GTK_WIDGET(window));
+
+ ci.loop = g_main_loop_new(NULL, FALSE);
+ g_main_loop_run(ci.loop);
+
+ gtk_widget_destroy(GTK_WIDGET(window));
+
+ return ci.response_id;
+}
diff --git a/src/spicy-connect.h b/src/spicy-connect.h
new file mode 100644
index 0000000..3f1869d
--- /dev/null
+++ b/src/spicy-connect.h
@@ -0,0 +1,26 @@
+/* -*- 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 <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef SPICY_CONNECT_H
+#define SPICY_CONNECT_H
+
+#include "spice-widget.h"
+
+int connect_dialog(SpiceSession *session);
+
+#endif
--
2.4.2
More information about the Spice-devel
mailing list