qemu-devel
[Top][All Lists]
Advanced

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

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


From: Programmingkid
Subject: [Qemu-devel] [PATCH] ui/cocoa.m: Add Mount image file menu item
Date: Tue, 1 Sep 2015 20:56:01 -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>

---
 ui/cocoa.m |  212 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 210 insertions(+), 1 deletions(-)

diff --git a/ui/cocoa.m b/ui/cocoa.m
index 334e6f6..6c0ec18 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -52,6 +52,9 @@
 #endif

 

 #define cgrect(nsrect) (*(CGRect *)&(nsrect))
+#define USB_DISK_ID "USB_DISK"
+#define EJECT_IMAGE_FILE_TAG 2099

 

 typedef struct {
     int width;
@@ -263,6 +266,43 @@ static void handleAnyDeviceErrors(Error * err)
     }
 }

 

+/* Sends a command to the monitor console */
+static void sendMonitorCommand(const char * commandString)
+{
+    int index;
+    char * consoleName;
+    static QemuConsole *monitor;
+
+    /* If the monitor console hasn't been found yet */
+    if(!monitor) {
+        index = 0;
+        /* Find the monitor console */
+        while (qemu_console_lookup_by_index(index) != NULL) {
+            consoleName = qemu_console_get_label(qemu_console_lookup_by_index(index));
+            if(strstr(consoleName, "monitor")) {
+                monitor = qemu_console_lookup_by_index(index);
+                break;
+            }
+            index++;
+        }
+    }
+
+    /* If the monitor console was not found */
+    if(!monitor) {
+        NSBeep();
+        QEMU_Alert(@"Failed to find the monitor console!");
+        return;
+    }
+
+    /* send each letter in the commandString to the monitor */
+    for (index = 0; index < strlen(commandString); index++) {
+        kbd_put_keysym_console(monitor, commandString[index]);
+    }
+
+    /* simulate the user pushing the return key */
+    kbd_put_keysym_console(monitor, '\n');
+}
+
 /*
  ------------------------------------------------------
     QemuCocoaView
@@ -585,6 +625,7 @@ QemuCocoaView *cocoaView;
             // forward command key combos to the host UI unless the mouse is grabbed
             if (!isMouseGrabbed && ([event modifierFlags] & NSCommandKeyMask)) {
                 [NSApp sendEvent:event];
+                printf("Returning\n");
                 return;
             }

 

@@ -829,6 +870,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 +1169,150 @@ 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;  // used for the ID
+        char *commandBuffer, *fileName, *idString, *fileNameHint;
+        NSString *buffer;
+        const int fileNameHintSize = 10;
+
+        fileName = g_strdup_printf("%s",
+                            [file cStringUsingEncoding: NSASCIIStringEncoding]);
+        buffer = [file lastPathComponent];
+        buffer = [buffer stringByDeletingPathExtension];
+        if([buffer length] > fileNameHintSize) {
+            buffer = [buffer substringToIndex: fileNameHintSize];
+        }
+        fileNameHint = g_strdup_printf("%s",
+                        [buffer cStringUsingEncoding: NSASCIIStringEncoding]);
+        idString = g_strdup_printf("%s_%s_%d", USB_DISK_ID, fileNameHint, usbDiskCount);
+        commandBuffer = g_strdup_printf("drive_add 0 if=none,id=%s,file=%s",
+                                                            idString, fileName);
+        sendMonitorCommand(commandBuffer);
+        commandBuffer = g_strdup_printf("device_add usb-storage,"
+                                         "id=%s,drive=%s", idString, idString);
+        sendMonitorCommand(commandBuffer);
+        [self updateEjectImageMenuItems];
+        usbDiskCount++;
+        g_free(fileName);
+        g_free(fileNameHint);
+        g_free(idString);
+        g_free(commandBuffer);
+    }
+}
+
+/* Removes an image file from QEMU */
+- (void)ejectImageFile:(id) sender
+{
+    char *commandBuffer;
+    NSString *imageFileID;
+
+    imageFileID = [sender representedObject];
+    if (imageFileID == nil) {
+        NSBeep();
+        QEMU_Alert(@"Could not find image file's ID!");
+        return;
+    }
+
+    commandBuffer = g_strdup_printf("drive_del %s",
+                    [imageFileID cStringUsingEncoding: NSASCIIStringEncoding]);
+    sendMonitorCommand(commandBuffer);
+    g_free(commandBuffer);
+
+    commandBuffer = g_strdup_printf("device_del %s",
+                        [imageFileID cStringUsingEncoding: NSASCIIStringEncoding]);
+    sendMonitorCommand(commandBuffer);
+    g_free(commandBuffer);
+
+    [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

 

 

@@ -1383,7 +1571,6 @@ static void addRemovableDevicesMenuItems()
     /* Loop thru all the block devices in the emulator */
     while (currentDevice) {
         deviceName = [[NSString stringWithFormat: @"%s", currentDevice->value->device] retain];
-
         if(currentDevice->value->removable) {
             menuItem = [[NSMenuItem alloc] initWithTitle: [NSString stringWithFormat: @"Change %s...", currentDevice->value->device]
                                                   action: @selector(changeDeviceMedia:)
@@ -1402,6 +1589,29 @@ static void addRemovableDevicesMenuItems()
         currentDevice = currentDevice->next;
     }
     qapi_free_BlockInfoList(pointerToFree);
+    [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 */
+    NSMenu *submenu;
+    submenu = [NSMenu new];
+    [ejectMenuItem setSubmenu: submenu];
+    [submenu addItem: emptyMenuItem];
+    [submenu autorelease];
 }

 

 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]