aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkraxel <kraxel>2008-09-30 12:14:49 +0000
committerkraxel <kraxel>2008-09-30 12:14:49 +0000
commiteb91e8c3ca50b3124b40e37a5c5836734eb36000 (patch)
tree5feaecb9453ce70ed9aff3069d98602349cbacfe
parentdefe66190b7e8b1c877b44d6cbb8a20b8eb13f24 (diff)
downloadqemu-gtk-eb91e8c3ca50b3124b40e37a5c5836734eb36000.tar.gz
- media change support.
-rw-r--r--GNUmakefile2
-rw-r--r--devices.c136
-rw-r--r--monitor.c29
-rw-r--r--qemu-gtk.c24
-rw-r--r--qemu-gtk.h9
5 files changed, 191 insertions, 9 deletions
diff --git a/GNUmakefile b/GNUmakefile
index 87aec2f..c79fb2f 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -57,7 +57,7 @@ realclean distclean: clean
#############################################
-qemu-gtk: qemu-gtk.o monitor.o tcp.o
+qemu-gtk: qemu-gtk.o monitor.o devices.o tcp.o
include mk/Compile.mk
include mk/Maintainer.mk
diff --git a/devices.c b/devices.c
new file mode 100644
index 0000000..07de700
--- /dev/null
+++ b/devices.c
@@ -0,0 +1,136 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <gtk/gtk.h>
+
+#include "qemu-gtk.h"
+
+/* ----------------------------------------------------------------- */
+
+static char mc_xml_start[] =
+"<ui>\n"
+" <menubar name='MainMenu'>\n"
+" <menu action='DevicesMenu'>\n"
+" <menu action='MediaChangeSubMenu'>\n";
+
+static char mc_xml_end[] =
+" </menu>\n"
+" </menu>\n"
+" </menubar>\n"
+"</ui>\n";
+
+/* ----------------------------------------------------------------- */
+
+static void menu_cb_change_media(GtkAction *action, void *data)
+{
+ struct qemu_window *win = data;
+ GtkWidget *dialog;
+ char *filename;
+ char name[32], title[128], cmd[128];
+
+ if (1 != sscanf(gtk_action_get_name(action), "ChangeMedia_%31s", name))
+ return;
+ if (debug)
+ fprintf(stderr, "%s: %s\n", __FUNCTION__, name);
+
+ snprintf(title, sizeof(title), "Pick image file for %s", name);
+ dialog = gtk_file_chooser_dialog_new (title, GTK_WINDOW(win->toplevel),
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
+ NULL);
+
+ if (gtk_dialog_run(GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
+ filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+ if (debug)
+ fprintf(stderr, "%s: %s\n", __FUNCTION__, filename);
+#if 0
+ /* not required it seems */
+ snprintf(cmd, sizeof(cmd), "eject %s", name);
+ monitor_append(win, cmd);
+#endif
+ snprintf(cmd, sizeof(cmd), "change %s %s", name, filename);
+ monitor_append(win, cmd);
+ monitor_append(win, "info block");
+ g_free (filename);
+ }
+ gtk_widget_destroy(dialog);
+}
+
+void devices_parse_info_block(struct qemu_window *win, char *str)
+{
+ char name[32], type[16], line[256], *file, *ptr;
+ char action[128], label[128];
+ int removable, pos, xpos, len, rc;
+ GtkActionEntry entry;
+ GError *err = NULL;
+ char *xml;
+
+ /* remove */
+ if (win->mc_id) {
+ gtk_ui_manager_remove_ui(win->ui, win->mc_id);
+ win->mc_id = 0;
+ }
+ if (win->mc_ag) {
+ gtk_ui_manager_remove_action_group(win->ui, win->mc_ag);
+ g_object_unref(win->mc_ag);
+ win->mc_ag = NULL;
+ }
+
+ /* start */
+ memset(&entry, 0, sizeof(entry));
+ entry.callback = G_CALLBACK(menu_cb_change_media);
+ win->mc_ag = gtk_action_group_new("ChangeMediaActions");
+
+ xpos = 0; xml = malloc(strlen(mc_xml_start)+1);
+ xpos += sprintf(xml+xpos, "%s", mc_xml_start);
+
+ /* parse & build */
+ for (pos = 0;; pos += len) {
+ rc = sscanf(str+pos, "%31[^:]: type=%15s removable=%d %255[^\r\n]%n",
+ name, type, &removable, line, &len);
+ if (rc != 4)
+ break;
+ while (str[pos+len] == '\r' || str[pos+len] == '\n')
+ len++;
+ if (!removable)
+ continue;
+ file = strstr(line, "file=");
+ if (file) {
+ file += 5;
+ ptr = strchr(file, ' ');
+ if (ptr)
+ *ptr = 0;
+ } else {
+ file = "<empty>";
+ }
+ if (debug)
+ fprintf(stderr, "%s: %s (%s, %s) - [%s]\n",
+ __FUNCTION__, name, type, file, line);
+
+ snprintf(action, sizeof(action), "ChangeMedia_%s", name);
+ snprintf(label, sizeof(label), "%s (%s, %s)", name, type, file);
+ xml = realloc(xml, xpos + 128);
+ xpos += snprintf(xml+xpos, 128, " <menuitem action='%s'/>\n", action);
+ entry.name = action;
+ entry.label = label;
+ gtk_action_group_add_actions(win->mc_ag, &entry, 1, win);
+ }
+
+ /* finish */
+ xml = realloc(xml, xpos + strlen(mc_xml_end)+1);
+ xpos += sprintf(xml+xpos, "%s", mc_xml_end);
+
+ /* add */
+ if (debug)
+ fprintf(stderr, "---\n%s---\n", xml);
+ gtk_ui_manager_insert_action_group(win->ui, win->mc_ag, 1);
+ win->mc_id = gtk_ui_manager_add_ui_from_string(win->ui, xml, -1, &err);
+ if (!win->mc_id) {
+ g_message("building media change menu failed: %s", err->message);
+ g_error_free(err);
+ }
+}
diff --git a/monitor.c b/monitor.c
index badb838..7189c5f 100644
--- a/monitor.c
+++ b/monitor.c
@@ -15,11 +15,18 @@
/* ----------------------------------------------------------------- */
+static void show_error(struct qemu_window *win, char *cmd, char *reply)
+{
+ /* FIXME: show error dialog */
+ fprintf(stderr, "ERROR: %s: %s\n", cmd, reply);
+}
+
static int monitor_parse(struct qemu_window *win, char *buf, int len)
{
char *reply, *prompt, *cmd;
int off;
+ /* handle vnc password change */
if (win->vnc_send_password && win->mrun &&
!strcmp(win->mrun->cmd, "change vnc password") &&
strstr(buf, "Password: "))
@@ -35,6 +42,7 @@ static int monitor_parse(struct qemu_window *win, char *buf, int len)
return 0;
}
+ /* parse buffer */
prompt = strstr(buf, "(qemu) ");
if (NULL == prompt) {
return 0;
@@ -57,15 +65,18 @@ static int monitor_parse(struct qemu_window *win, char *buf, int len)
goto out;
}
reply += 2;
-
if (debug)
fprintf(stderr, "%s: \"%s\" -> [%s]\n", __FUNCTION__, cmd, reply);
+
+ /* parse reply */
if (0 == strcmp(cmd, "info version")) {
snprintf(win->version, sizeof(win->version), "%s", reply);
update_status(win);
+
} else if (0 == strcmp(cmd, "info name")) {
snprintf(win->name, sizeof(win->name), "%s", reply);
update_status(win);
+
} else if (0 == strcmp(cmd, "info vnc")) {
if (1 == sscanf(reply, "VNC server active on: %127[^\r\n]",
win->vnc_display) &&
@@ -83,8 +94,16 @@ static int monitor_parse(struct qemu_window *win, char *buf, int len)
vnc_connect(win);
}
}
+
} else if (0 == strcmp(cmd, "change vnc password")) {
vnc_connect(win);
+
+ } else if (0 == strcmp(cmd, "info block")) {
+ devices_parse_info_block(win, reply);
+
+ } else if (0 == strncmp(cmd, "eject ", 6) ||
+ 0 == strncmp(cmd, "change ", 7)) {
+ show_error(win, cmd, reply);
}
out:
@@ -118,11 +137,16 @@ void monitor_append(struct qemu_window *win, char *cmd)
;
mq->next = malloc(sizeof(*mq));
mq = mq->next;
+ if (debug)
+ fprintf(stderr, "%s: tail: %s\n", __FUNCTION__, cmd);
} else {
win->mqueue = malloc(sizeof(*mq));
mq = win->mqueue;
- if (!win->mused && win->msize)
+ if (!win->mrun && !win->mused && win->msize)
try_send = 1;
+ if (debug)
+ fprintf(stderr, "%s: %s: %s\n", __FUNCTION__,
+ try_send ? "send" : "head", cmd);
}
mq->next = NULL;
snprintf(mq->cmd, sizeof(mq->cmd), "%s", cmd);
@@ -200,5 +224,6 @@ int monitor_connect(struct qemu_window *win, char *dest)
monitor_append(win, "info version");
monitor_append(win, "info name");
monitor_append(win, "info vnc");
+ monitor_append(win, "info block");
return fd;
}
diff --git a/qemu-gtk.c b/qemu-gtk.c
index c105835..b5a03ee 100644
--- a/qemu-gtk.c
+++ b/qemu-gtk.c
@@ -416,6 +416,7 @@ static int conn_connect(struct qemu_conn *conn, char *name, char *dest)
static const GtkActionEntry entries[] = {
{
+ /* --- menu bar --- */
.name = "FileMenu",
.label = "_File",
},{
@@ -428,22 +429,33 @@ static const GtkActionEntry entries[] = {
.name = "VMMenu",
.label = "_VM",
},{
+ .name = "DevicesMenu",
+ .label = "_Devices",
+ },{
.name = "HelpMenu",
.label = "_Help",
+ },{
+ /* --- sub menus --- */
+ .name = "MediaChangeSubMenu",
+ .label = "_Change media",
},{
+
+ /* --- file menu --- */
.name = "Close",
.stock_id = GTK_STOCK_CLOSE,
.label = "_Close",
.accelerator = "<control>Q",
.callback = G_CALLBACK(menu_cb_close),
-
},{
+
+ /* --- input menu --- */
.name = "SendCtrlAltDel",
.label = "Send Ctrl-Alt-Del",
.callback = G_CALLBACK(menu_cb_send_ctrlaltdel),
-
},{
+
+ /* --- vm menu --- */
.name = "MonitorStop",
.stock_id = GTK_STOCK_MEDIA_PAUSE,
.label = "_Pause",
@@ -461,13 +473,13 @@ static const GtkActionEntry entries[] = {
.name = "MonitorSysPowerdown",
.label = "_Shutdown",
.callback = G_CALLBACK(menu_cb_monitor_sys_powerdown),
-
},{
.name = "RunGdb",
.label = "_Debug with gdb",
.callback = G_CALLBACK(menu_cb_run_gdb),
-
},{
+
+ /* --- help menu --- */
.name = "About",
.stock_id = GTK_STOCK_ABOUT,
.label = "_About ...",
@@ -522,6 +534,10 @@ static char ui_xml[] =
" <separator/>"
" <menuitem action='RunGdb'/>"
" </menu>"
+" <menu action='DevicesMenu'>"
+" <menu action='MediaChangeSubMenu'>"
+" </menu>"
+" </menu>"
" <menu action='HelpMenu'>"
" <menuitem action='About'/>"
" </menu>"
diff --git a/qemu-gtk.h b/qemu-gtk.h
index ab4a309..4e63d8c 100644
--- a/qemu-gtk.h
+++ b/qemu-gtk.h
@@ -2,7 +2,7 @@ struct qemu_window;
struct qemu_mq {
struct qemu_mq *next;
- char cmd[64];
+ char cmd[128];
};
enum vnc_state {
@@ -52,6 +52,10 @@ struct qemu_window {
struct qemu_mq *mqueue;
struct qemu_mq *mrun;
+ /* devices */
+ GtkActionGroup *mc_ag;
+ guint mc_id;
+
/* gdb */
GtkWidget *gdb_vte;
pid_t gdb_pid;
@@ -76,4 +80,5 @@ void qemu_conn_tab(struct qemu_window *win, struct qemu_conn *conn, int pos);
int monitor_connect(struct qemu_window *win, char *dest);
void monitor_append(struct qemu_window *win, char *cmd);
-
+/* devices.c */
+void devices_parse_info_block(struct qemu_window *win, char *str);