From patchwork Thu Sep 10 22:27:06 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Programmingkid X-Patchwork-Id: 516481 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 5FA9C140783 for ; Fri, 11 Sep 2015 08:42:41 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b=T2DIeYWl; dkim-atps=neutral Received: from localhost ([::1]:52380 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZaAYA-00025A-Ve for incoming@patchwork.ozlabs.org; Thu, 10 Sep 2015 18:42:38 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41348) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZaAXg-0001cc-DZ for qemu-devel@nongnu.org; Thu, 10 Sep 2015 18:42:13 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ZaAJE-0006NF-21 for qemu-devel@nongnu.org; Thu, 10 Sep 2015 18:28:37 -0400 Received: from mail-qg0-x235.google.com ([2607:f8b0:400d:c04::235]:36603) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZaAJD-0006LC-In for qemu-devel@nongnu.org; Thu, 10 Sep 2015 18:27:11 -0400 Received: by qgx61 with SMTP id 61so48743105qgx.3 for ; Thu, 10 Sep 2015 15:27:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:content-type:subject:date:message-id:cc:to:mime-version; bh=VeJZw0GLu+fm2D8tB1iKfylZvI9fj2NrmngGcaIsJ0E=; b=T2DIeYWlgXsG+Ke17+2M2qH8DUbkrcS4c4k1sDfHyluun2l9WEzU1b9emg66t0arXf Ot9+XHU/xDIPfknZkzmYMcOZRawl9WScex1YaUzfBAXLTg7bUebUvuQTs43FGKhyej2E aCr90pi2j0WDxJ+HzxJI0Exh+uqeq5TPU5tU9GDK/bf/muDTGDYz83nrqCy0UQAVWvgB PtvZhX67j7N2WZ7MylBOKvYdVzGcHigutNdD6EapWPHpysuoKL67pt5xUqe63wgUo5Nz pNsHxJ9bqihCvT/ZCxanEoSfwZ0Fytq+TbiU2Q9+td6Ze9RVSAKsThch3qtE6Xbftj3F H6Ng== X-Received: by 10.140.86.70 with SMTP id o64mr57364769qgd.52.1441924028723; Thu, 10 Sep 2015 15:27:08 -0700 (PDT) Received: from [192.168.0.3] (d199-74-164-53.col.wideopenwest.com. [74.199.53.164]) by smtp.gmail.com with ESMTPSA id 125sm6795249qha.41.2015.09.10.15.27.07 (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 10 Sep 2015 15:27:07 -0700 (PDT) From: Programmingkid Date: Thu, 10 Sep 2015 18:27:06 -0400 Message-Id: <153FBDBF-2650-4D9E-BFC1-3D838BCC30F3@gmail.com> To: Peter Maydell Mime-Version: 1.0 (Apple Message framework v1084) X-Mailer: Apple Mail (2.1084) X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2607:f8b0:400d:c04::235 Cc: qemu-devel qemu-devel Subject: [Qemu-devel] [PATCH v2] ui/cocoa.m: Add Mount image file menu item X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Add "Mount Image File..." and a "Eject Image File" menu items to cocoa interface. This patch makes sharing files between the host and the guest user-friendly. The "Mount Image File..." menu item displays a dialog box having the user pick an image file to use in QEMU. The image file is setup as a USB flash drive. The user can do the equivalent of removing the flash drive by selecting the file in the "Eject Image File" submenu. Signed-off-by: John Arbuckle --- Detects if the user actually specified the -usb option. Removed the sendMonitorCommand() function. Replaced a lot of code with C interface equivalent of monitor commands drive_add and device_add. ui/cocoa.m | 228 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 227 insertions(+), 1 deletions(-) diff --git a/ui/cocoa.m b/ui/cocoa.m index 334e6f6..df1faea 100644 --- a/ui/cocoa.m +++ b/ui/cocoa.m @@ -31,6 +31,8 @@ #include "sysemu/sysemu.h" #include "qmp-commands.h" #include "sysemu/blockdev.h" +#include "include/monitor/qdev.h" +#include "hw/boards.h" #ifndef MAC_OS_X_VERSION_10_5 #define MAC_OS_X_VERSION_10_5 1050 @@ -52,6 +54,8 @@ #endif #define cgrect(nsrect) (*(CGRect *)&(nsrect)) +#define USB_DISK_ID "USB_DISK" +#define EJECT_IMAGE_FILE_TAG 2099 typedef struct { int width; @@ -829,6 +833,9 @@ QemuCocoaView *cocoaView; - (void)powerDownQEMU:(id)sender; - (void)ejectDeviceMedia:(id)sender; - (void)changeDeviceMedia:(id)sender; +- (void)mountImageFile:(id)sender; +- (void)ejectImageFile:(id)sender; +- (void)updateEjectImageMenuItems; @end @implementation QemuCocoaAppController @@ -1125,6 +1132,179 @@ QemuCocoaView *cocoaView; } } +/* Displays a dialog box asking the user for an image file to mount */ +- (void)mountImageFile:(id)sender +{ + /* Display the file open dialog */ + NSOpenPanel * openPanel; + openPanel = [NSOpenPanel openPanel]; + [openPanel setCanChooseFiles: YES]; + [openPanel setAllowsMultipleSelection: NO]; + [openPanel setAllowedFileTypes: supportedImageFileTypes]; + if([openPanel runModal] == NSFileHandlingPanelOKButton) { + NSString * file = [[[openPanel URLs] objectAtIndex: 0] path]; + if(file == nil) { + NSBeep(); + QEMU_Alert(@"Failed to convert URL to file path!"); + return; + } + + static int usbDiskCount; + char *idString, *fileName, *driveOptions, *fileNameHint; + + /* Create the file name hint */ + NSString *stringBuffer; + const int fileNameHintSize = 10; + stringBuffer = [file lastPathComponent]; + stringBuffer = [stringBuffer stringByDeletingPathExtension]; + if([stringBuffer length] > fileNameHintSize) { + stringBuffer = [stringBuffer substringToIndex: fileNameHintSize]; + } + fileNameHint = g_strdup_printf("%s", + [stringBuffer cStringUsingEncoding: NSASCIIStringEncoding]); + + idString = g_strdup_printf("%s_%s_%d", USB_DISK_ID, fileNameHint, + usbDiskCount++); + + fileName = g_strdup_printf("%s", + [file cStringUsingEncoding: NSASCIIStringEncoding]); + + /* drive_add equivalent code */ + driveOptions = g_strdup_printf("if=none,id=%s,file=%s", idString, + fileName); + DriveInfo *dinfo; + QemuOpts *opts; + MachineClass *mc; + + opts = drive_def(driveOptions); + if (!opts) { + QEMU_Alert(@"Error: could not create QemuOpts object!"); + return; + } + + mc = MACHINE_GET_CLASS(current_machine); + dinfo = drive_new(opts, mc->block_default_type); + if (!dinfo) { + qemu_opts_del(opts); + QEMU_Alert(@"Error: could not create DriveInfo object!"); + return; + } + + /* device_add equivalent code */ + + /* Create the QDict object */ + QDict * qdict; + qdict = qdict_new(); + qdict_set_default_str(qdict, "driver", "usb-storage"); + qdict_set_default_str(qdict, "id", idString); + qdict_set_default_str(qdict, "drive", idString); + + QObject *ret_data; + ret_data = g_malloc(1); /* This is just to silence a warning */ + + Error *errp = NULL; + qmp_device_add(qdict, &ret_data, &errp); + handleAnyDeviceErrors(errp); + [self updateEjectImageMenuItems]; + + g_free(qdict); + g_free(fileName); + g_free(idString); + g_free(driveOptions); + g_free(ret_data); + } +} + +/* Removes an image file from QEMU */ +- (void)ejectImageFile:(id) sender +{ + NSString *imageFileID; + + imageFileID = [sender representedObject]; + if (imageFileID == nil) { + NSBeep(); + QEMU_Alert(@"Could not find image file's ID!"); + return; + } + + Error *errp = NULL; + qmp_device_del([imageFileID cStringUsingEncoding: NSASCIIStringEncoding], + &errp); + handleAnyDeviceErrors(errp); + [self updateEjectImageMenuItems]; +} + +/* Gives each mounted image file an eject menu item */ +- (void) updateEjectImageMenuItems +{ + NSMenu *machineMenu; + machineMenu = [[[NSApp mainMenu] itemWithTitle:@"Machine"] submenu]; + + /* Remove old menu items*/ + NSMenu * ejectSubmenu; + ejectSubmenu = [[machineMenu itemWithTag: EJECT_IMAGE_FILE_TAG] submenu]; + if(!ejectSubmenu) { + NSBeep(); + QEMU_Alert(@"Failed to find eject submenu!"); + return; + } + int index; + for (index = 0; index < [ejectSubmenu numberOfItems]; index++) { + [ejectSubmenu removeItemAtIndex: 0]; + } + /* Needed probably because of a bug with cocoa */ + if ([ejectSubmenu numberOfItems] > 0) { + [ejectSubmenu removeItemAtIndex: 0]; + } + + BlockInfoList *currentDevice; + currentDevice = qmp_query_block(NULL); + + NSString *fileName, *deviceName; + NSMenuItem *ejectFileMenuItem; /* Used with each mounted image file */ + + /* Look for mounted image files */ + while(currentDevice) { + if (!currentDevice->value || !currentDevice->value->inserted + || !currentDevice->value->inserted->file) { + currentDevice = currentDevice->next; + continue; + } + + /* if the device's name is the generated ID */ + if (!strstr(currentDevice->value->device, USB_DISK_ID)) { + currentDevice = currentDevice->next; + continue; + } + + fileName = [NSString stringWithFormat: @"%s", currentDevice->value->inserted->file]; + fileName = [fileName lastPathComponent]; /* To obtain only the file name */ + + ejectFileMenuItem = [[NSMenuItem alloc] initWithTitle: [NSString stringWithFormat: @"Eject %@", fileName] + action: @selector(ejectImageFile:) + keyEquivalent: @""]; + [ejectSubmenu addItem: ejectFileMenuItem]; + deviceName = [NSString stringWithFormat: @"%s", currentDevice->value->device]; + [ejectFileMenuItem setRepresentedObject: deviceName]; + [ejectFileMenuItem autorelease]; + currentDevice = currentDevice->next; + } + + /* Add default menu item if submenu is empty */ + if([ejectSubmenu numberOfItems] == 0) { + + /* Create the default menu item */ + NSMenuItem *emptyMenuItem; + emptyMenuItem = [NSMenuItem new]; + [emptyMenuItem setTitle: @"No items available"]; + [emptyMenuItem setEnabled: NO]; + + /* Add the default menu item to the submenu */ + [ejectSubmenu addItem: emptyMenuItem]; + [emptyMenuItem release]; + } +} + @end @@ -1338,10 +1518,52 @@ static void add_console_menu_entries(void) } } +/* Determines if USB is available */ +static bool usbAvailable(void) +{ + /* Look thru all the arguments sent to QEMU for '-usb' */ + int index; + for (index = 0; index < gArgc; index++) { + if(strcmp(gArgv[index], "-usb") == 0) { + return true; + } + } + return false; +} + +/* Adds menu items that can mount an image file like a usb flash drive */ +static void addImageMountingMenus(NSMenu *menu) +{ + [menu addItem: [[[NSMenuItem alloc] initWithTitle: @"Mount Image File..." + action: @selector(mountImageFile:) keyEquivalent: @""] autorelease]]; + + /* Create the eject menu item */ + NSMenuItem *ejectMenuItem; + ejectMenuItem = [NSMenuItem new]; + [ejectMenuItem setTitle: @"Eject Image File"]; + [ejectMenuItem setTag: EJECT_IMAGE_FILE_TAG]; + [menu addItem: ejectMenuItem]; + [ejectMenuItem autorelease]; + + /* Create the default menu item for the eject menu item's submenu*/ + NSMenuItem *emptyMenuItem; + emptyMenuItem = [NSMenuItem new]; + [emptyMenuItem setTitle: @"No items available"]; + [emptyMenuItem setEnabled: NO]; + [emptyMenuItem autorelease]; + + /* Add the default menu item to the submenu, the "No items" menu item */ + NSMenu *submenu; + submenu = [NSMenu new]; + [ejectMenuItem setSubmenu: submenu]; + [submenu addItem: emptyMenuItem]; + [submenu autorelease]; +} + /* Make menu items for all removable devices. * Each device is given an 'Eject' and 'Change' menu item. */ -static void addRemovableDevicesMenuItems() +static void addRemovableDevicesMenuItems(void) { NSMenu *menu; NSMenuItem *menuItem; @@ -1402,6 +1624,10 @@ static void addRemovableDevicesMenuItems() currentDevice = currentDevice->next; } qapi_free_BlockInfoList(pointerToFree); + + if(usbAvailable() == true){ + addImageMountingMenus(menu); + } } void cocoa_display_init(DisplayState *ds, int full_screen)