qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH v2] ui/cocoa.m: Add Mount image file menu item


From: Programmingkid
Subject: [Qemu-devel] [PATCH v2] ui/cocoa.m: Add Mount image file menu item
Date: Thu, 10 Sep 2015 18:27:06 -0400

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 <address@hidden>

---
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)
-- 
1.7.5.4


reply via email to

[Prev in Thread] Current Thread [Next in Thread]