diff options
author | Gerd Hoffmann <kraxel@redhat.com> | 2012-08-15 16:49:39 +0200 |
---|---|---|
committer | Gerd Hoffmann <kraxel@redhat.com> | 2012-08-15 16:49:39 +0200 |
commit | daf23c350f0fe8fffbbde331d43460c517d3e445 (patch) | |
tree | 8afe6a21c38ffb961b7cbba89107d3f996e6d02e /domain.c | |
download | vconsole-daf23c350f0fe8fffbbde331d43460c517d3e445.tar.gz |
initial commit
Diffstat (limited to 'domain.c')
-rw-r--r-- | domain.c | 331 |
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); +} + |