aboutsummaryrefslogtreecommitdiffstats
path: root/domain.c
diff options
context:
space:
mode:
authorGerd Hoffmann <kraxel@redhat.com>2012-08-15 16:49:39 +0200
committerGerd Hoffmann <kraxel@redhat.com>2012-08-15 16:49:39 +0200
commitdaf23c350f0fe8fffbbde331d43460c517d3e445 (patch)
tree8afe6a21c38ffb961b7cbba89107d3f996e6d02e /domain.c
downloadvconsole-daf23c350f0fe8fffbbde331d43460c517d3e445.tar.gz
initial commit
Diffstat (limited to 'domain.c')
-rw-r--r--domain.c331
1 files changed, 331 insertions, 0 deletions
diff --git a/domain.c b/domain.c
new file mode 100644
index 0000000..465aded
--- /dev/null
+++ b/domain.c
@@ -0,0 +1,331 @@
+#include "vconsole.h"
+
+/* ------------------------------------------------------------------ */
+
+static const char *state_name[] = {
+ [ VIR_DOMAIN_NOSTATE ] = "-",
+ [ VIR_DOMAIN_RUNNING ] = "running",
+ [ VIR_DOMAIN_BLOCKED ] = "blocked",
+ [ VIR_DOMAIN_PAUSED ] = "paused",
+ [ VIR_DOMAIN_SHUTDOWN ] = "shutdown",
+ [ VIR_DOMAIN_SHUTOFF ] = "shutoff",
+ [ VIR_DOMAIN_CRASHED ] = "crashed",
+ [ VIR_DOMAIN_PMSUSPENDED ] = "suspended",
+};
+
+static const char *domain_state_name(struct vconsole_domain *dom)
+{
+ if (dom->info.state < sizeof(state_name)/sizeof(state_name[0]))
+ return state_name[dom->info.state];
+ return "-?-";
+}
+
+/* ------------------------------------------------------------------ */
+
+static void domain_configure_vte(struct vconsole_domain *dom)
+{
+ struct vconsole_window *win = dom->conn->win;
+ VteTerminal *vte = VTE_TERMINAL(dom->vte);
+ VteTerminalCursorBlinkMode bl =
+ win->tty_blink ? VTE_CURSOR_BLINK_ON : VTE_CURSOR_BLINK_OFF;
+ GdkColor fg = {0,0,0,0};
+ GdkColor bg = {0,0,0,0};
+
+ gdk_color_parse(win->tty_fg, &fg);
+ gdk_color_parse(win->tty_bg, &bg);
+
+ vte_terminal_set_font_from_string(vte, win->tty_font);
+ vte_terminal_set_cursor_blink_mode(vte, bl);
+ vte_terminal_set_color_foreground(vte, &fg);
+ vte_terminal_set_color_background(vte, &bg);
+}
+
+void domain_configure_all_vtes(struct vconsole_window *win)
+{
+ GtkTreeModel *model = GTK_TREE_MODEL(win->store);
+ GtkTreeIter host, guest;
+ struct vconsole_domain *dom;
+ int rc;
+
+ rc = gtk_tree_model_get_iter_first(model, &host);
+ while (rc) {
+ rc = gtk_tree_model_iter_nth_child(model, &guest, &host, 0);
+ while (rc) {
+ gtk_tree_model_get(model, &guest,
+ DPTR_COL, &dom,
+ -1);
+ if (dom->vte)
+ domain_configure_vte(dom);
+ rc = gtk_tree_model_iter_next(model, &guest);
+ }
+ rc = gtk_tree_model_iter_next(model, &host);
+ }
+}
+
+static void domain_update_status(struct vconsole_domain *dom)
+{
+ char line[128];
+
+ if (!dom->status)
+ return;
+ snprintf(line, sizeof(line), "%s%s",
+ domain_state_name(dom),
+ dom->stream ? ", connected" : "");
+ gtk_label_set_text(GTK_LABEL(dom->status), line);
+}
+
+static void domain_disconnect(struct vconsole_domain *dom, virDomainPtr d)
+{
+ if (!dom->stream)
+ return;
+
+ if (debug)
+ fprintf(stderr, "%s: %s\n", __func__, virDomainGetName(d));
+ virStreamEventRemoveCallback(dom->stream);
+ virStreamFree(dom->stream);
+ dom->stream = NULL;
+ domain_update_status(dom);
+}
+
+static void domain_console_event(virStreamPtr stream, int events, void *opaque)
+{
+ struct vconsole_domain *dom = opaque;
+ virDomainPtr d = virDomainLookupByUUIDString(dom->conn->ptr, dom->uuid);
+ const char *name = virDomainGetName(d);
+ char buf[128];
+ int rc, bytes = 0;
+
+ if (events & VIR_STREAM_EVENT_READABLE) {
+ for (;;) {
+ rc = virStreamRecv(stream, buf, sizeof(buf));
+ if (rc <= 0)
+ break;
+ bytes += rc;
+ if (dom->vte)
+ vte_terminal_feed(VTE_TERMINAL(dom->vte), buf, rc);
+ }
+ if (bytes == 0) {
+ if (debug)
+ fprintf(stderr, "%s: %s eof\n", __func__, name);
+ domain_disconnect(dom, d);
+ }
+ }
+ if (events & VIR_STREAM_EVENT_HANGUP) {
+ if (debug)
+ fprintf(stderr, "%s: %s hangup\n", __func__, name);
+ domain_disconnect(dom, d);
+ }
+}
+
+static void domain_user_input(VteTerminal *vte, gchar *buf, guint len,
+ gpointer opaque)
+{
+ struct vconsole_domain *dom = opaque;
+ virDomainPtr d;
+
+ if (dom->stream) {
+ virStreamSend(dom->stream, buf, len);
+ return;
+ }
+ if (dom->info.state == VIR_DOMAIN_SHUTOFF) {
+ d = virDomainLookupByUUIDString(dom->conn->ptr, dom->uuid);
+ virDomainCreate(d);
+ }
+}
+
+static void domain_connect(struct vconsole_domain *dom, virDomainPtr d)
+{
+ int rc;
+
+ if (dom->stream)
+ return;
+
+ dom->stream = virStreamNew(dom->conn->ptr,
+ VIR_STREAM_NONBLOCK);
+ rc = virDomainOpenConsole(d, NULL, dom->stream,
+ VIR_DOMAIN_CONSOLE_FORCE);
+ if (rc < 0) {
+ if (debug)
+ fprintf(stderr, "%s: %s failed\n", __func__, virDomainGetName(d));
+ virStreamFree(dom->stream);
+ dom->stream = NULL;
+ return;
+ }
+
+ virStreamEventAddCallback(dom->stream,
+ VIR_STREAM_EVENT_READABLE |
+ VIR_STREAM_EVENT_HANGUP,
+ domain_console_event, dom, NULL);
+ if (debug)
+ fprintf(stderr, "%s: %s ok\n", __func__, virDomainGetName(d));
+ domain_update_status(dom);
+}
+
+/* ------------------------------------------------------------------ */
+
+void domain_update(struct vconsole_connect *conn,
+ virDomainPtr d, virDomainEventType event)
+{
+ GtkTreeModel *model = GTK_TREE_MODEL(conn->win->store);
+ GtkTreeIter host, guest;
+ struct vconsole_domain *dom = NULL;
+ void *ptr;
+ gboolean rc;
+ const char *name;
+ char uuid[VIR_UUID_STRING_BUFLEN];
+ char idstr[16];
+ int id;
+
+ /* find host */
+ rc = gtk_tree_model_get_iter_first(model, &host);
+ while (rc) {
+ gtk_tree_model_get(model, &host,
+ CPTR_COL, &ptr,
+ -1);
+ if (ptr == conn)
+ break;
+ rc = gtk_tree_model_iter_next(model, &host);
+ }
+ assert(ptr == conn);
+
+ /* find guest */
+ virDomainGetUUIDString(d, uuid);
+ rc = gtk_tree_model_iter_nth_child(model, &guest, &host, 0);
+ while (rc) {
+ gtk_tree_model_get(model, &guest,
+ DPTR_COL, &dom,
+ -1);
+ if (strcmp(uuid, dom->uuid) == 0)
+ break;
+ dom = NULL;
+ rc = gtk_tree_model_iter_next(model, &guest);
+ }
+
+ /* no guest found -> create new */
+ if (dom == NULL) {
+ dom = g_new0(struct vconsole_domain, 1);
+ dom->conn = conn;
+ virDomainGetUUIDString(d, dom->uuid);
+ gtk_tree_store_append(conn->win->store, &guest, &host);
+ gtk_tree_store_set(conn->win->store, &guest,
+ DPTR_COL, dom, -1);
+ }
+
+ /* handle events */
+ switch (event) {
+ case VIR_DOMAIN_EVENT_UNDEFINED:
+ fprintf(stderr, "%s: undefined %s [ FIXME ]\n", __func__,
+ virDomainGetName(d));
+ break;
+ case VIR_DOMAIN_EVENT_STARTED:
+ domain_connect(dom, d);
+ break;
+ case VIR_DOMAIN_EVENT_STOPPED:
+ domain_disconnect(dom, d);
+ break;
+ default:
+ break;
+ }
+
+ /* update guest info */
+ name = virDomainGetName(d);
+ id = virDomainGetID(d);
+ if (id < 0)
+ strcpy(idstr, "-");
+ else
+ snprintf(idstr, sizeof(idstr), "%d", id);
+ virDomainGetInfo(d, &dom->info);
+ gtk_tree_store_set(conn->win->store, &guest,
+ NAME_COL, name,
+ ID_COL, idstr,
+ STATE_COL, domain_state_name(dom),
+ -1);
+ domain_update_status(dom);
+}
+
+void domain_activate(struct vconsole_domain *dom)
+{
+ virDomainPtr d = virDomainLookupByUUIDString(dom->conn->ptr, dom->uuid);
+ struct vconsole_window *win = dom->conn->win;
+ GtkWidget *label, *fstatus;
+ const char *name;
+
+ if (dom->vte) {
+ gtk_notebook_set_current_page(GTK_NOTEBOOK(win->notebook), dom->page);
+ } else {
+ name = virDomainGetName(d);
+ if (debug)
+ fprintf(stderr, "new tab: %s\n", name);
+
+ dom->vte = vte_terminal_new();
+ g_signal_connect(dom->vte, "commit",
+ G_CALLBACK(domain_user_input), dom);
+
+ dom->status = gtk_label_new("-");
+ gtk_misc_set_alignment(GTK_MISC(dom->status), 0, 0.5);
+ gtk_misc_set_padding(GTK_MISC(dom->status), 3, 1);
+
+ dom->vbox = gtk_vbox_new(FALSE, 1);
+ gtk_container_set_border_width(GTK_CONTAINER(dom->vbox), 1);
+ gtk_box_pack_start(GTK_BOX(dom->vbox), dom->vte, TRUE, TRUE, 0);
+ fstatus = gtk_frame_new(NULL);
+ gtk_box_pack_end(GTK_BOX(dom->vbox), fstatus, FALSE, TRUE, 0);
+ gtk_container_add(GTK_CONTAINER(fstatus), dom->status);
+
+ label = gtk_label_new(name);
+ dom->page = gtk_notebook_insert_page(GTK_NOTEBOOK(win->notebook),
+ dom->vbox, label, -1);
+ gtk_widget_show_all(dom->vbox);
+ gtk_notebook_set_current_page(GTK_NOTEBOOK(win->notebook), dom->page);
+ domain_configure_vte(dom);
+ domain_update_status(dom);
+ }
+
+ domain_connect(dom, d);
+}
+
+static void domain_close_tab(struct vconsole_domain *dom)
+{
+ virDomainPtr d = virDomainLookupByUUIDString(dom->conn->ptr, dom->uuid);
+
+ domain_disconnect(dom, d);
+ gtk_notebook_remove_page(GTK_NOTEBOOK(dom->conn->win->notebook), dom->page);
+ dom->vbox = NULL;
+ dom->vte = NULL;
+ dom->status = NULL;
+}
+
+static struct vconsole_domain *domain_find_current_tab(struct vconsole_window *win)
+{
+ GtkTreeModel *model = GTK_TREE_MODEL(win->store);
+ GtkTreeIter host, guest;
+ struct vconsole_domain *dom;
+ int rc, page;
+
+ page = gtk_notebook_get_current_page(GTK_NOTEBOOK(win->notebook));
+ rc = gtk_tree_model_get_iter_first(model, &host);
+ while (rc) {
+ rc = gtk_tree_model_iter_nth_child(model, &guest, &host, 0);
+ while (rc) {
+ gtk_tree_model_get(model, &guest,
+ DPTR_COL, &dom,
+ -1);
+ if (dom->vbox && dom->page == page) {
+ return dom;
+ }
+ rc = gtk_tree_model_iter_next(model, &guest);
+ }
+ rc = gtk_tree_model_iter_next(model, &host);
+ }
+ return NULL;
+}
+
+void domain_close_current_tab(struct vconsole_window *win)
+{
+ struct vconsole_domain *dom;
+
+ dom = domain_find_current_tab(win);
+ if (dom)
+ domain_close_tab(dom);
+}
+