#include #include #include #include #include #include #include "qemu-gtk.h" /* ----------------------------------------------------------------- */ static char media_xml[] = "\n" " \n" " \n" " \n" "%s" " \n" " \n" "%s" " \n" " \n" " \n" "\n"; static char plug_usb_xml[] = "\n" " \n" " \n" " \n" "%s" " \n" " \n" " \n" "\n"; static char unplug_usb_xml[] = "\n" " \n" " \n" " \n" "%s" " \n" " \n" " \n" "\n"; static char open_term_xml[] = "\n" " \n" " \n" " \n" "%s" " \n" " \n" " \n" "\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); } static void menu_cb_eject_media(GtkAction *action, void *data) { struct qemu_window *win = data; char name[32], cmd[128]; if (1 != sscanf(gtk_action_get_name(action), "EjectMedia_%31s", name)) return; if (debug) fprintf(stderr, "%s: %s\n", __FUNCTION__, name); snprintf(cmd, sizeof(cmd), "eject %s", name); monitor_append(win, cmd); 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 menu_cb_open_term(GtkAction *action, void *data) { struct qemu_window *win = data; char name[32], file[256]; if (2 != sscanf(gtk_action_get_name(action), "OpenTerm_%[^_]_%255s", name, file)) return; if (1 || debug) fprintf(stderr, "%s: %s -- %s\n", __FUNCTION__, name, file); conn_open_term(win, name, file, -1); } /* ----------------------------------------------------------------- */ 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, " \n", action); } static int skip_line(char *str, int pos) { char line[256]; int rc, len; rc = sscanf(str+pos, "%255[^\r\n]%n", line, &len); if (1 != rc || 0 == len) return 0; fprintf(stderr, "can't parse \"%s\", skipping\n", line); while (str[pos+len] == '\r' || str[pos+len] == '\n') len++; return len; } static int menu_del(struct qemu_window *win, struct qemu_menu *menu) { if (menu->id) { gtk_ui_manager_remove_ui(win->ui, menu->id); menu->id = 0; } if (menu->ag) { gtk_ui_manager_remove_action_group(win->ui, menu->ag); g_object_unref(menu->ag); menu->ag = NULL; } return 0; } static int menu_add(struct qemu_window *win, struct qemu_menu *menu, char *xml) { GError *err = NULL; if (debug) fprintf(stderr, "---\n%s---\n", xml); gtk_ui_manager_insert_action_group(win->ui, menu->ag, 1); menu->id = gtk_ui_manager_add_ui_from_string(win->ui, xml, -1, &err); if (!menu->id) { g_message("building menu failed: %s", err->message); g_error_free(err); return -1; } return 0; } /* ----------------------------------------------------------------- */ void devices_parse_info_block(struct qemu_window *win, char *str) { char name[32], type[16], line[256], *file, *ptr, *xml; char label[128]; int removable, pos, len, rc, eject; char *c_xml = NULL, *e_xml = NULL; int c_pos = 0, e_pos = 0; /* remove */ menu_del(win, &win->mc); /* start */ win->mc.ag = gtk_action_group_new("MediaActions"); /* 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) { /* parse error, try to skip line */ if (0 == (len = skip_line(str, pos))) break; continue; } 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; #if 1 /* basename */ ptr = strrchr(file, '/'); if (ptr) file = ptr+1; #endif eject = 1; } else { file = ""; eject = 0; } if (debug) fprintf(stderr, "%s: %s (%s, %s) - [%s]\n", __FUNCTION__, name, type, file, line); snprintf(label, sizeof(label), "%s (%s, %s)", name, type, file); add_entry(win, win->mc.ag, menu_cb_change_media, &c_xml, &c_pos, label, "ChangeMedia", name); if (eject) { snprintf(label, sizeof(label), "%s (%s, %s)", name, type, file); 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, c_pos ? c_xml : "", e_pos ? e_xml : ""); /* add */ menu_add(win, &win->mc, xml); free(c_xml); 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]; int pos, len, rc; char *i_xml = NULL; int i_pos = 0; /* remove */ menu_del(win, &win->usb); /* 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) { /* parse error, try to skip line */ if (0 == (len = skip_line(str, pos))) break; continue; } 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 */ menu_add(win, &win->usb, xml); 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]; int pos, len, rc, vendor, product; char *i_xml = NULL; int i_pos = 0; /* remove */ menu_del(win, &win->usbhost); /* 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) { strcpy(name, "no name"); rc = sscanf(str+pos, " Device %15[^,], speed %15s Mb/s\n" " %31[^:]: USB device %x:%x%n", device, speed, class, &vendor, &product, &len); if (rc != 5) { /* parse error, try to skip line */ if (0 == (len = skip_line(str, pos))) break; continue; } } while (str[pos+len] == '\r' || str[pos+len] == '\n') len++; if (0 == strcmp("Hub", class)) continue; if (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 */ menu_add(win, &win->usbhost, xml); free(i_xml); free(xml); } void devices_parse_info_chardev(struct qemu_window *win, char *str) { char name[32], file[256], *xml; char action[128], label[128]; int pos, len, rc; char *i_xml = NULL; int i_pos = 0; /* remove */ menu_del(win, &win->chardev); /* start */ win->chardev.ag = gtk_action_group_new("OpenTermActions"); /* parse & build */ for (pos = 0;; pos += len) { rc = sscanf(str+pos, "%31[^:]: filename=%255[^\r\n]%n", name, file, &len); if (rc != 2) { /* parse error, try to skip line */ if (0 == (len = skip_line(str, pos))) break; continue; } while (str[pos+len] == '\r' || str[pos+len] == '\n') len++; if (debug) fprintf(stderr, "%s: %s -- \"%s\"\n", __FUNCTION__, name, file); /* filter out stuff */ if (strcmp(name, "monitor") == 0) continue; if (strcmp(name, "gdb") == 0) continue; if (strncmp(file, "vc:", 3) == 0) continue; if (strncmp(file, "null", 4) == 0) continue; /* save away first serial */ if (strcmp(name, "serial0") == 0) { free(win->sercon); win->sercon = strdup(file); } snprintf(label, sizeof(label), "%s", name); snprintf(action, sizeof(action), "%s_%s", name, file); add_entry(win, win->chardev.ag, menu_cb_open_term, &i_xml, &i_pos, label, "OpenTerm", action); } xml = malloc(i_pos + strlen(open_term_xml)); sprintf(xml, open_term_xml, i_pos ? i_xml : ""); /* add */ menu_add(win, &win->chardev, xml); 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"); monitor_append(win, "info chardev"); }