aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkraxel <kraxel>2008-10-17 22:46:47 +0000
committerkraxel <kraxel>2008-10-17 22:46:47 +0000
commit99537ea7f5f0622656b2a85e93fadcf875216349 (patch)
treead29fe74cc01c69f921d861de8348441225d152c
parent3b6bd0694fa18ad018c2aff3611996097ece0acd (diff)
downloadqemu-gtk-99537ea7f5f0622656b2a85e93fadcf875216349.tar.gz
- usb hotplug
-rw-r--r--devices.c235
-rw-r--r--monitor.c26
-rw-r--r--qemu-gtk.c33
-rw-r--r--qemu-gtk.h7
4 files changed, 267 insertions, 34 deletions
diff --git a/devices.c b/devices.c
index 7d76580..a8cb8bd 100644
--- a/devices.c
+++ b/devices.c
@@ -14,10 +14,32 @@ static char media_xml[] =
"<ui>\n"
" <menubar name='MainMenu'>\n"
" <menu action='DevicesMenu'>\n"
+" <menu action='ChangeMediaSubMenu'>\n"
+"%s"
+" </menu>\n"
" <menu action='EjectMediaSubMenu'>\n"
"%s"
" </menu>\n"
-" <menu action='ChangeMediaSubMenu'>\n"
+" </menu>\n"
+" </menubar>\n"
+"</ui>\n";
+
+static char plug_usb_xml[] =
+"<ui>\n"
+" <menubar name='MainMenu'>\n"
+" <menu action='DevicesMenu'>\n"
+" <menu action='PlugUsbSubMenu'>\n"
+"%s"
+" </menu>\n"
+" </menu>\n"
+" </menubar>\n"
+"</ui>\n";
+
+static char unplug_usb_xml[] =
+"<ui>\n"
+" <menubar name='MainMenu'>\n"
+" <menu action='DevicesMenu'>\n"
+" <menu action='UnplugUsbSubMenu'>\n"
"%s"
" </menu>\n"
" </menu>\n"
@@ -77,12 +99,63 @@ static void menu_cb_eject_media(GtkAction *action, void *data)
monitor_append(win, "info block");
}
+static void menu_cb_plug_usb(GtkAction *action, void *data)
+{
+ struct qemu_window *win = data;
+ char device[32], cmd[128];
+
+ if (1 != sscanf(gtk_action_get_name(action), "PlugUsb_%31s", device))
+ return;
+ if (debug)
+ fprintf(stderr, "%s: %s\n", __FUNCTION__, device);
+
+ snprintf(cmd, sizeof(cmd), "usb_add %s", device);
+ monitor_append(win, cmd);
+ monitor_append(win, "info usb");
+}
+
+static void menu_cb_unplug_usb(GtkAction *action, void *data)
+{
+ struct qemu_window *win = data;
+ char device[32], cmd[128];
+
+ if (1 != sscanf(gtk_action_get_name(action), "UnplugUsb_%31s", device))
+ return;
+ if (debug)
+ fprintf(stderr, "%s: %s\n", __FUNCTION__, device);
+
+ snprintf(cmd, sizeof(cmd), "usb_del %s", device);
+ monitor_append(win, cmd);
+ monitor_append(win, "info usb");
+}
+
+/* ----------------------------------------------------------------- */
+
+static void add_entry(struct qemu_window *win,
+ GtkActionGroup *ag,
+ void (*cb)(GtkAction *action, void *data),
+ char **i_xml, int *i_pos,
+ char *label, char *type, char *name)
+{
+ GtkActionEntry entry;
+ char action[128];
+
+ snprintf(action, sizeof(action), "%s_%s", type, name);
+ memset(&entry, 0, sizeof(entry));
+ entry.callback = G_CALLBACK(cb);
+ entry.name = action;
+ entry.label = label;
+ gtk_action_group_add_actions(ag, &entry, 1, win);
+ *i_xml = realloc(*i_xml, (*i_pos) + 128);
+ *i_pos += snprintf((*i_xml)+(*i_pos), 128,
+ " <menuitem action='%s'/>\n", action);
+}
+
void devices_parse_info_block(struct qemu_window *win, char *str)
{
char name[32], type[16], line[256], *file, *ptr, *xml;
- char action[128], label[128];
+ char label[128];
int removable, pos, len, rc, eject;
- GtkActionEntry c_entry, e_entry;
char *c_xml = NULL, *e_xml = NULL;
int c_pos = 0, e_pos = 0;
GError *err = NULL;
@@ -99,10 +172,6 @@ void devices_parse_info_block(struct qemu_window *win, char *str)
}
/* start */
- memset(&c_entry, 0, sizeof(c_entry));
- c_entry.callback = G_CALLBACK(menu_cb_change_media);
- memset(&e_entry, 0, sizeof(e_entry));
- e_entry.callback = G_CALLBACK(menu_cb_eject_media);
win->mc_ag = gtk_action_group_new("MediaActions");
/* parse & build */
@@ -135,29 +204,21 @@ void devices_parse_info_block(struct qemu_window *win, char *str)
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);
- c_entry.name = action;
- c_entry.label = label;
- gtk_action_group_add_actions(win->mc_ag, &c_entry, 1, win);
- c_xml = realloc(c_xml, c_pos + 128);
- c_pos += snprintf(c_xml+c_pos, 128, " <menuitem action='%s'/>\n", action);
+ add_entry(win, win->mc_ag, menu_cb_change_media, &c_xml, &c_pos,
+ label, "ChangeMedia", name);
if (eject) {
- snprintf(action, sizeof(action), "EjectMedia_%s", name);
snprintf(label, sizeof(label), "%s (%s, %s)", name, type, file);
- e_entry.name = action;
- e_entry.label = label;
- gtk_action_group_add_actions(win->mc_ag, &e_entry, 1, win);
- e_xml = realloc(e_xml, e_pos + 128);
- e_pos += snprintf(e_xml+e_pos, 128, " <menuitem action='%s'/>\n", action);
+ add_entry(win, win->mc_ag, menu_cb_eject_media, &e_xml, &e_pos,
+ label, "EjectMedia", name);
}
}
xml = malloc(e_pos + c_pos + strlen(media_xml));
sprintf(xml, media_xml,
- e_pos ? e_xml : "",
- c_pos ? c_xml : "");
+ c_pos ? c_xml : "",
+ e_pos ? e_xml : "");
/* add */
if (debug)
@@ -173,3 +234,135 @@ void devices_parse_info_block(struct qemu_window *win, char *str)
free(e_xml);
free(xml);
}
+
+void devices_parse_info_usb(struct qemu_window *win, char *str)
+{
+ char device[16], name[64], speed[16], *xml;
+ char label[128];
+ GError *err = NULL;
+ int pos, len, rc;
+ char *i_xml = NULL;
+ int i_pos = 0;
+
+ /* remove */
+ if (win->usb_id) {
+ gtk_ui_manager_remove_ui(win->ui, win->usb_id);
+ win->usb_id = 0;
+ }
+ if (win->usb_ag) {
+ gtk_ui_manager_remove_action_group(win->ui, win->usb_ag);
+ g_object_unref(win->usb_ag);
+ win->usb_ag = NULL;
+ }
+
+ /* start */
+ win->usb_ag = gtk_action_group_new("UnplugUsbActions");
+
+ /* parse & build */
+ for (pos = 0;; pos += len) {
+ rc = sscanf(str+pos, " Device %15[^,], Speed %15s Mb/s, Product %63[^\r\n]%n",
+ device, speed, name, &len);
+ if (rc != 3)
+ break;
+ while (str[pos+len] == '\r' || str[pos+len] == '\n')
+ len++;
+ if (debug)
+ fprintf(stderr, "%s: %s - %s - %s\n",
+ __FUNCTION__, device, speed, name);
+
+ snprintf(label, sizeof(label), "%s (%s)", name, device);
+ add_entry(win, win->usb_ag, menu_cb_unplug_usb, &i_xml, &i_pos,
+ label, "UnplugUsb", device);
+ }
+
+ xml = malloc(i_pos + strlen(unplug_usb_xml));
+ sprintf(xml, unplug_usb_xml,
+ i_pos ? i_xml : "");
+
+ /* add */
+ if (debug)
+ fprintf(stderr, "---\n%s---\n", xml);
+ gtk_ui_manager_insert_action_group(win->ui, win->usb_ag, 1);
+ win->usb_id = gtk_ui_manager_add_ui_from_string(win->ui, xml, -1, &err);
+ if (!win->usb_id) {
+ g_message("building unplug usb menu failed: %s", err->message);
+ g_error_free(err);
+ }
+
+ free(i_xml);
+ free(xml);
+}
+
+void devices_parse_info_usbhost(struct qemu_window *win, char *str)
+{
+ char device[16], speed[16], class[32], name[64], *xml;
+ char action[128], label[128];
+ GError *err = NULL;
+ int pos, len, rc, vendor, product;
+ char *i_xml = NULL;
+ int i_pos = 0;
+
+ /* remove */
+ if (win->usbhost_id) {
+ gtk_ui_manager_remove_ui(win->ui, win->usbhost_id);
+ win->usbhost_id = 0;
+ }
+ if (win->usbhost_ag) {
+ gtk_ui_manager_remove_action_group(win->ui, win->usbhost_ag);
+ g_object_unref(win->usbhost_ag);
+ win->usbhost_ag = NULL;
+ }
+
+ /* start */
+ win->usbhost_ag = gtk_action_group_new("PlugUsbActions");
+
+ /* parse & build */
+ for (pos = 0;; pos += len) {
+ rc = sscanf(str+pos,
+ " Device %15[^,], speed %15s Mb/s\n"
+ " %31[^:]: USB device %x:%x, %63[^\r\n]%n",
+ device, speed, class, &vendor, &product, name, &len);
+ if (rc != 6)
+ break;
+ while (str[pos+len] == '\r' || str[pos+len] == '\n')
+ len++;
+ if (0 == strcmp("Hub", class))
+ continue;
+ if (1 || debug)
+ fprintf(stderr, "%s: %s (%04x:%04x) - %s - %s\n",
+ __FUNCTION__, device, vendor, product, class, name);
+
+ snprintf(label, sizeof(label), "%s (host %s)", name, device);
+ snprintf(action, sizeof(action), "host:%s", device);
+ add_entry(win, win->usbhost_ag, menu_cb_plug_usb, &i_xml, &i_pos,
+ label, "PlugUsb", action);
+ }
+
+ /* static */
+ add_entry(win, win->usbhost_ag, menu_cb_plug_usb, &i_xml, &i_pos,
+ "QEMU USB Tablet (virtual)", "PlugUsb", "tablet");
+
+ xml = malloc(i_pos + strlen(plug_usb_xml));
+ sprintf(xml, plug_usb_xml,
+ i_pos ? i_xml : "");
+
+ /* add */
+ if (debug)
+ fprintf(stderr, "---\n%s---\n", xml);
+ gtk_ui_manager_insert_action_group(win->ui, win->usbhost_ag, 1);
+ win->usbhost_id = gtk_ui_manager_add_ui_from_string(win->ui, xml, -1, &err);
+ if (!win->usbhost_id) {
+ g_message("building host usb menu failed: %s", err->message);
+ g_error_free(err);
+ }
+
+ free(i_xml);
+ free(xml);
+}
+
+void devices_rescan(struct qemu_window *win)
+{
+ monitor_append(win, "info block");
+ monitor_append(win, "info usb");
+ monitor_append(win, "info usbhost");
+}
diff --git a/monitor.c b/monitor.c
index 8e6bc4c..083d53b 100644
--- a/monitor.c
+++ b/monitor.c
@@ -70,13 +70,14 @@ static int monitor_parse(struct qemu_window *win, char *buf, int len)
cmd = win->mrun->cmd;
reply = strstr(buf, "\r\n");
if (!reply) {
+ reply = "";
if (debug)
- fprintf(stderr, "%s: no reply for \"%s\"\n", __FUNCTION__, cmd);
- goto out;
+ fprintf(stderr, "%s: empty reply for \"%s\"\n", __FUNCTION__, cmd);
+ } else {
+ reply += 2;
+ if (debug)
+ fprintf(stderr, "%s: \"%s\" -> [%s]\n", __FUNCTION__, cmd, reply);
}
- reply += 2;
- if (debug)
- fprintf(stderr, "%s: \"%s\" -> [%s]\n", __FUNCTION__, cmd, reply);
/* parse reply */
if (0 == strcmp(cmd, "info version")) {
@@ -111,9 +112,18 @@ static int monitor_parse(struct qemu_window *win, char *buf, int len)
} else if (0 == strcmp(cmd, "info block")) {
devices_parse_info_block(win, reply);
+ } else if (0 == strcmp(cmd, "info usb")) {
+ devices_parse_info_usb(win, reply);
+
+ } else if (0 == strcmp(cmd, "info usbhost")) {
+ devices_parse_info_usbhost(win, reply);
+
} else if (0 == strncmp(cmd, "eject ", 6) ||
- 0 == strncmp(cmd, "change ", 7)) {
- show_error(win, cmd, reply);
+ 0 == strncmp(cmd, "change ", 7) ||
+ 0 == strncmp(cmd, "usb_add ", 8) ||
+ 0 == strncmp(cmd, "usb_del ", 8)) {
+ if (strlen(reply))
+ show_error(win, cmd, reply);
}
out:
@@ -234,6 +244,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");
+ devices_rescan(win);
return fd;
}
diff --git a/qemu-gtk.c b/qemu-gtk.c
index ff18d6c..5ab68a6 100644
--- a/qemu-gtk.c
+++ b/qemu-gtk.c
@@ -101,7 +101,6 @@ static void vte_configure(struct qemu_window *win, GtkWidget *vte)
vte_terminal_set_backspace_binding(VTE_TERMINAL(vte),
VTE_ERASE_ASCII_BACKSPACE);
- fprintf(stderr, "%s: %s %s\n", __FUNCTION__, win->tty_fg, win->tty_bg);
gdk_color_parse(win->tty_fg, &fg);
gdk_color_parse(win->tty_bg, &bg);
vte_terminal_set_color_foreground(VTE_TERMINAL(vte), &fg);
@@ -227,6 +226,7 @@ static void menu_cb_config_font(GtkAction *action, void *data)
win->tty_font = gtk_font_selection_dialog_get_font_name
(GTK_FONT_SELECTION_DIALOG(dialog));
g_key_file_set_string(config, "tty", "font", win->tty_font);
+ config_dirty++;
vtes_set_font(win);
break;
}
@@ -254,6 +254,7 @@ static int pickcolor(char *title, char *group, char *key, char *current)
snprintf(name, sizeof(name), "#%04x%04x%04x",
color.red, color.green, color.blue);
g_key_file_set_string(config, group, key, name);
+ config_dirty++;
rc = 0;
}
gtk_widget_destroy(dialog);
@@ -292,6 +293,12 @@ static void menu_cb_send_ctrlaltdel(GtkToggleAction *action, gpointer userdata)
VNC_DISPLAY_KEY_EVENT_CLICK);
}
+static void menu_cb_devices_rescan(GtkToggleAction *action, gpointer userdata)
+{
+ struct qemu_window *win = userdata;
+ devices_rescan(win);
+}
+
static void menu_cb_about(GtkAction *action, gpointer userdata)
{
static char *comments = "gtk ui for qemu";
@@ -595,11 +602,17 @@ static const GtkActionEntry entries[] = {
},{
/* --- sub menus --- */
+ .name = "ChangeMediaSubMenu",
+ .label = "_Change media",
+ },{
.name = "EjectMediaSubMenu",
.label = "_Eject media",
},{
- .name = "ChangeMediaSubMenu",
- .label = "_Change media",
+ .name = "PlugUsbSubMenu",
+ .label = "_Plugin USB",
+ },{
+ .name = "UnplugUsbSubMenu",
+ .label = "_Unplug USB",
},{
/* --- file menu --- */
@@ -656,6 +669,12 @@ static const GtkActionEntry entries[] = {
.callback = G_CALLBACK(menu_cb_run_gdb),
},{
+ /* --- devices menu --- */
+ .name = "DevicesRescan",
+ .label = "_Rescan devices",
+ .callback = G_CALLBACK(menu_cb_devices_rescan),
+ },{
+
/* --- help menu --- */
.name = "About",
.stock_id = GTK_STOCK_ABOUT,
@@ -716,8 +735,12 @@ static char ui_xml[] =
" <menuitem action='RunGdb'/>"
" </menu>"
" <menu action='DevicesMenu'>"
-" <menu action='EjectMediaSubMenu'/>"
" <menu action='ChangeMediaSubMenu'/>"
+" <menu action='EjectMediaSubMenu'/>"
+" <menu action='PlugUsbSubMenu'/>"
+" <menu action='UnplugUsbSubMenu'/>"
+" <separator/>"
+" <menuitem action='DevicesRescan'/>"
" </menu>"
" <menu action='HelpMenu'>"
" <menuitem action='About'/>"
@@ -812,7 +835,7 @@ static struct qemu_window *qemu_create_window(void)
win->tty_bg = g_key_file_get_string(config, "tty", "background", &err);
/* config defaults */
- if (!win->tty_fg)
+ if (!win->tty_font)
win->tty_font = "console 12";
if (!win->tty_fg)
win->tty_fg = "white";
diff --git a/qemu-gtk.h b/qemu-gtk.h
index bccd665..2740e9a 100644
--- a/qemu-gtk.h
+++ b/qemu-gtk.h
@@ -55,6 +55,10 @@ struct qemu_window {
/* devices */
GtkActionGroup *mc_ag;
guint mc_id;
+ GtkActionGroup *usb_ag;
+ guint usb_id;
+ GtkActionGroup *usbhost_ag;
+ guint usbhost_id;
/* gdb */
GtkWidget *gdb_vte;
@@ -88,3 +92,6 @@ void monitor_append(struct qemu_window *win, char *cmd);
/* devices.c */
void devices_parse_info_block(struct qemu_window *win, char *str);
+void devices_parse_info_usb(struct qemu_window *win, char *str);
+void devices_parse_info_usbhost(struct qemu_window *win, char *str);
+void devices_rescan(struct qemu_window *win);