|
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 |
[Prev in Thread] | Current Thread | [Next in Thread] |