From: Anthony Liguori <aliguori@us.ibm.com>
To: qemu-devel@nongnu.org
Cc: Anthony Liguori <aliguori@us.ibm.com>
Subject: [Qemu-devel] [PATCH 3/7] gtk: add virtual console support (v2)
Date: Wed, 5 Sep 2012 14:18:40 -0500 [thread overview]
Message-ID: <1346872724-9156-4-git-send-email-aliguori@us.ibm.com> (raw)
In-Reply-To: <1346872724-9156-1-git-send-email-aliguori@us.ibm.com>
This enables VteTerminal to be used to render the text consoles. VteTerminal is
the same widget used by gnome-terminal which means it's VT100 emulation is as
good as they come.
It's also screen reader accessible, supports copy/paste, proper scrolling and
most of the other features you would expect from a terminal widget.
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
v1 -> v2
- make sure to activate the menu item when switching tabs
- fix sizing of non-0 pages
- fix build with newer gcc
---
ui/gtk.c | 159 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 159 insertions(+), 0 deletions(-)
diff --git a/ui/gtk.c b/ui/gtk.c
index e724956..0bcb3c2 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -56,6 +56,8 @@
#define dprintf(fmt, ...) do { } while (0)
#endif
+#define MAX_VCS 10
+
typedef struct VirtualConsole
{
GtkWidget *menu_item;
@@ -79,6 +81,9 @@ typedef struct GtkDisplayState
GtkWidget *view_menu;
GtkWidget *vga_item;
+ int nb_vcs;
+ VirtualConsole vc[MAX_VCS];
+
GtkWidget *show_tabs_item;
GtkWidget *vbox;
@@ -400,6 +405,15 @@ static void gd_menu_switch_vc(GtkMenuItem *item, void *opaque)
if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->vga_item))) {
gtk_notebook_set_current_page(GTK_NOTEBOOK(s->notebook), 0);
+ } else {
+ int i;
+
+ for (i = 0; i < s->nb_vcs; i++) {
+ if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(s->vc[i].menu_item))) {
+ gtk_notebook_set_current_page(GTK_NOTEBOOK(s->notebook), i + 1);
+ break;
+ }
+ }
}
}
@@ -418,16 +432,153 @@ static void gd_change_page(GtkNotebook *nb, gpointer arg1, guint arg2,
gpointer data)
{
GtkDisplayState *s = data;
+ guint last_page;
if (!gtk_widget_get_realized(s->notebook)) {
return;
}
+ last_page = gtk_notebook_get_current_page(nb);
+
+ if (last_page) {
+ gtk_widget_set_size_request(s->vc[last_page - 1].terminal, -1, -1);
+ }
+
+ if (arg2 == 0) {
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(s->vga_item), TRUE);
+ } else {
+ VirtualConsole *vc = &s->vc[arg2 - 1];
+ VteTerminal *term = VTE_TERMINAL(vc->terminal);
+ int width, height;
+
+ width = 80 * vte_terminal_get_char_width(term);
+ height = 25 * vte_terminal_get_char_height(term);
+
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(vc->menu_item), TRUE);
+ gtk_widget_set_size_request(vc->terminal, width, height);
+ }
+
gd_update_cursor(s, TRUE);
}
+/** Virtual Console Callbacks **/
+
+static int gd_vc_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+ VirtualConsole *vc = chr->opaque;
+
+ return write(vc->fd, buf, len);
+}
+
+static int nb_vcs;
+static CharDriverState *vcs[MAX_VCS];
+
+static CharDriverState *gd_vc_handler(QemuOpts *opts)
+{
+ CharDriverState *chr;
+
+ chr = g_malloc0(sizeof(*chr));
+ chr->chr_write = gd_vc_chr_write;
+
+ vcs[nb_vcs++] = chr;
+
+ return chr;
+}
+
void early_gtk_display_init(void)
{
+ register_vc_handler(gd_vc_handler);
+}
+
+static gboolean gd_vc_in(GIOChannel *chan, GIOCondition cond, void *opaque)
+{
+ VirtualConsole *vc = opaque;
+ uint8_t buffer[1024];
+ ssize_t len;
+
+ len = read(vc->fd, buffer, sizeof(buffer));
+ if (len <= 0) {
+ return FALSE;
+ }
+
+ qemu_chr_be_write(vc->chr, buffer, len);
+
+ return TRUE;
+}
+
+static GSList *gd_vc_init(GtkDisplayState *s, VirtualConsole *vc, int index, GSList *group)
+{
+ const char *label;
+ char buffer[32];
+ char path[32];
+ VtePty *pty;
+ GIOChannel *chan;
+ GtkWidget *scrolled_window;
+ GtkAdjustment *vadjustment;
+ int master_fd, slave_fd, ret;
+ struct termios tty;
+
+ snprintf(buffer, sizeof(buffer), "vc%d", index);
+ snprintf(path, sizeof(path), "<QEMU>/View/VC%d", index);
+
+ vc->chr = vcs[index];
+
+ if (vc->chr->label) {
+ label = vc->chr->label;
+ } else {
+ label = buffer;
+ }
+
+ vc->menu_item = gtk_radio_menu_item_new_with_mnemonic(group, label);
+ group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(vc->menu_item));
+ gtk_menu_item_set_accel_path(GTK_MENU_ITEM(vc->menu_item), path);
+ gtk_accel_map_add_entry(path, GDK_KEY_2 + index, GDK_CONTROL_MASK | GDK_MOD1_MASK);
+
+ vc->terminal = vte_terminal_new();
+
+ ret = openpty(&master_fd, &slave_fd, NULL, NULL, NULL);
+ g_assert(ret != -1);
+
+ /* Set raw attributes on the pty. */
+ tcgetattr(slave_fd, &tty);
+ cfmakeraw(&tty);
+ tcsetattr(slave_fd, TCSAFLUSH, &tty);
+
+ pty = vte_pty_new_foreign(master_fd, NULL);
+
+ vte_terminal_set_pty_object(VTE_TERMINAL(vc->terminal), pty);
+
+ vte_terminal_set_scrollback_lines(VTE_TERMINAL(vc->terminal), -1);
+
+ vadjustment = vte_terminal_get_adjustment(VTE_TERMINAL(vc->terminal));
+
+ scrolled_window = gtk_scrolled_window_new(NULL, vadjustment);
+ gtk_container_add(GTK_CONTAINER(scrolled_window), vc->terminal);
+
+ vte_terminal_set_size(VTE_TERMINAL(vc->terminal), 80, 25);
+
+ vc->fd = slave_fd;
+ vc->chr->opaque = vc;
+ vc->scrolled_window = scrolled_window;
+
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(vc->scrolled_window),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+
+ gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook), scrolled_window, gtk_label_new(label));
+ g_signal_connect(vc->menu_item, "activate",
+ G_CALLBACK(gd_menu_switch_vc), s);
+
+ gtk_menu_append(GTK_MENU(s->view_menu), vc->menu_item);
+
+ qemu_chr_generic_open(vc->chr);
+ if (vc->chr->init) {
+ vc->chr->init(vc->chr);
+ }
+
+ chan = g_io_channel_unix_new(vc->fd);
+ g_io_add_watch(chan, G_IO_IN, gd_vc_in, vc);
+
+ return group;
}
/** Window Creation **/
@@ -467,6 +618,7 @@ static void gd_create_menus(GtkDisplayState *s)
GtkAccelGroup *accel_group;
GSList *group = NULL;
GtkWidget *separator;
+ int i;
accel_group = gtk_accel_group_new();
s->file_menu = gtk_menu_new();
@@ -493,6 +645,13 @@ static void gd_create_menus(GtkDisplayState *s)
gtk_accel_map_add_entry("<QEMU>/View/VGA", GDK_KEY_1, GDK_CONTROL_MASK | GDK_MOD1_MASK);
gtk_menu_append(GTK_MENU(s->view_menu), s->vga_item);
+ for (i = 0; i < nb_vcs; i++) {
+ VirtualConsole *vc = &s->vc[i];
+
+ group = gd_vc_init(s, vc, i, group);
+ s->nb_vcs++;
+ }
+
separator = gtk_separator_menu_item_new();
gtk_menu_append(GTK_MENU(s->view_menu), separator);
--
1.7.5.4
next prev parent reply other threads:[~2012-09-05 19:19 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-09-05 19:18 [Qemu-devel] [PATCH 0/7] Add GTK UI to enable basic accessibility (v3) Anthony Liguori
2012-09-05 19:18 ` [Qemu-devel] [PATCH 1/7] console: allow VCs to be overridden by UI Anthony Liguori
2012-09-05 19:18 ` [Qemu-devel] [PATCH 2/7] ui: add basic GTK gui (v2) Anthony Liguori
2012-09-05 19:53 ` Blue Swirl
2012-09-05 20:00 ` Eric Blake
2012-09-05 20:38 ` Anthony Liguori
2012-09-05 21:00 ` Blue Swirl
2012-09-05 23:07 ` Anthony Liguori
2012-09-08 7:00 ` Blue Swirl
2012-09-05 20:04 ` Stefan Weil
2012-09-05 20:39 ` Anthony Liguori
2012-09-05 20:45 ` Jan Kiszka
2012-09-05 22:55 ` Anthony Liguori
2012-09-05 20:54 ` Jan Kiszka
2012-09-05 19:18 ` Anthony Liguori [this message]
2012-09-05 19:18 ` [Qemu-devel] [PATCH 4/7] gtk: add support for input grabbing (v2) Anthony Liguori
2012-09-05 19:37 ` Jan Kiszka
2012-09-05 20:40 ` Anthony Liguori
2012-09-05 20:43 ` Jan Kiszka
2012-09-05 19:18 ` [Qemu-devel] [PATCH 5/7] gtk: add support for screen scaling and full screen (v3) Anthony Liguori
2012-09-05 19:18 ` [Qemu-devel] [PATCH 6/7] gtk: add translation support Anthony Liguori
2012-09-06 12:18 ` Kevin Wolf
2012-09-06 12:40 ` Anthony Liguori
2012-09-06 13:00 ` Peter Maydell
2012-09-05 19:18 ` [Qemu-devel] [PATCH 7/7] gtk: make default UI (v3) Anthony Liguori
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1346872724-9156-4-git-send-email-aliguori@us.ibm.com \
--to=aliguori@us.ibm.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).