Added features: Menu items to switch floppy and CD image files. Menu items to eject floppy and CD image files. Menu item to use /dev/cdrom. Verifies with the user before quitting QEMU by displaying a dialog box.
Signed-off-by: John Arbuckle <programmingk...@gmail.com> --- Added yellow background to the pause label. Removed all depreciated methods. Using strncpy() in place of strcpy() in emulatorHasDevice() . Eliminated all warnings when compiling. ui/cocoa.m | 238 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 237 insertions(+), 1 deletions(-) diff --git a/ui/cocoa.m b/ui/cocoa.m index d37c29b..0e4a327 100644 --- a/ui/cocoa.m +++ b/ui/cocoa.m @@ -29,6 +29,8 @@ #include "ui/console.h" #include "ui/input.h" #include "sysemu/sysemu.h" +#include "qmp-commands.h" +#include "sysemu/blockdev.h" #ifndef MAC_OS_X_VERSION_10_4 #define MAC_OS_X_VERSION_10_4 1040 @@ -64,6 +66,9 @@ static int last_buttons; int gArgc; char **gArgv; +#define MAX_DEVICE_NAME_SIZE 10 +char floppy_drive_name[MAX_DEVICE_NAME_SIZE], cdrom_drive_name[MAX_DEVICE_NAME_SIZE]; +NSTextField * pause_label; // keymap conversion int keymap[] = @@ -239,7 +244,95 @@ static int cocoa_keycode_to_qemu(int keycode) return keymap[keycode]; } +/* Handles any errors that happen with a device transaction */ +static void handleAnyDeviceErrors(Error * err) +{ + if (err) { + NSRunAlertPanel(@"Alert", [NSString stringWithCString: error_get_pretty(err) encoding: NSASCIIStringEncoding], @"OK", nil, nil); + error_free(err); + } +} + +/* +Determine if the current emulator has the specified device. +device_name: the name of the device you want: floppy, cd +official_name: QEMU's name for the device: floppy0, ide-cd0 +*/ +static bool emulatorHasDevice(const char * device_name, char * official_name) +{ + BlockInfoList * block_device_data; + block_device_data = qmp_query_block(false); + if(block_device_data == NULL) { + return false; + } + while(block_device_data->next != NULL) { + /* If we found the device */ + if (strstr(block_device_data->value->device, device_name)) { + strncpy(official_name, block_device_data->value->device, MAX_DEVICE_NAME_SIZE); + qapi_free_BlockInfoList(block_device_data); + return true; + } + block_device_data = block_device_data->next; + } + return false; +} + +/* Determine if the current emulator has a floppy drive */ +static bool emulatorHasFloppy() +{ + if (emulatorHasDevice("floppy", floppy_drive_name)) { + return true; + } else { + return false; + } +} + +/* Determine if the current emulator has a CDROM drive */ +static bool emulatorHasCDROM() +{ + if (emulatorHasDevice("cd", cdrom_drive_name)) { + return true; + } else { + return false; + } +} + +/* Adds the Machine menu to the menu bar. */ +/* Has to be added separately because QEMU needs + to be running to determine used devices. +*/ +static void createMachineMenu() +{ + NSMenu * menu; + NSMenuItem * menuItem; + + // Machine menu + menu = [[NSMenu alloc] initWithTitle: @"Machine"]; + [menu setAutoenablesItems: NO]; + [menu addItem: [[[NSMenuItem alloc] initWithTitle: @"Pause" action: @selector(pauseQemu:) keyEquivalent: @""] autorelease]]; + [menu addItem: [[[NSMenuItem alloc] initWithTitle: @"Resume" action: @selector(resumeQemu:) keyEquivalent: @""] autorelease]]; + + if(emulatorHasFloppy() || emulatorHasCDROM()) { + [menu addItem: [NSMenuItem separatorItem]]; + } + if (emulatorHasFloppy()) { + [menu addItem: [[[NSMenuItem alloc] initWithTitle: @"Eject Floppy" action: @selector(ejectFloppy:) keyEquivalent: @""] autorelease]]; + [menu addItem: [[[NSMenuItem alloc] initWithTitle: @"Change Floppy..." action: @selector(changeFloppy:) keyEquivalent: @""] autorelease]]; + } + if (emulatorHasCDROM()) { + [menu addItem: [[[NSMenuItem alloc] initWithTitle: @"Eject cdrom" action: @selector(ejectCdrom:) keyEquivalent: @""] autorelease]]; + [menu addItem: [[[NSMenuItem alloc] initWithTitle: @"Use cdrom image..." action: @selector(changeCdrom:) keyEquivalent: @""] autorelease]]; + [menu addItem: [[[NSMenuItem alloc] initWithTitle: @"Use real cdrom drive" action: @selector(useRealCdrom:) keyEquivalent: @""] autorelease]]; + } + [menu addItem: [NSMenuItem separatorItem]]; + [menu addItem: [[[NSMenuItem alloc] initWithTitle: @"Reset" action: @selector(restartQemu:) keyEquivalent: @""] autorelease]]; + [menu addItem: [[[NSMenuItem alloc] initWithTitle: @"Power Down" action: @selector(powerDown:) keyEquivalent: @""] autorelease]]; + menuItem = [[[NSMenuItem alloc] initWithTitle: @"Machine" action:nil keyEquivalent:@""] autorelease]; + [menuItem setSubmenu:menu]; + [[NSApp mainMenu] insertItem: menuItem atIndex: 2]; /* Insert after View menu */ + [[menu itemWithTitle: @"Resume"] setEnabled: NO]; +} /* ------------------------------------------------------ @@ -801,6 +894,17 @@ QemuCocoaView *cocoaView; - (void)toggleFullScreen:(id)sender; - (void)showQEMUDoc:(id)sender; - (void)showQEMUTec:(id)sender; +- (void)pauseQemu:(id)sender; +- (void)ejectFloppy:(id)sender; +- (void)ejectCdrom:(id)sender; +- (void)changeCdrom:(id)sender; +- (void)changeFloppy:(id)sender; +- (void)restartQemu:(id)sender; +- (void)useRealCdrom:(id)sender; +- (void)verifyQuit:(id)sender; +- (void)powerDown:(id)sender; +- (void)displayPause; +- (void)removePause; @end @implementation QemuCocoaAppController @@ -833,6 +937,22 @@ QemuCocoaView *cocoaView; [normalWindow makeKeyAndOrderFront:self]; [normalWindow center]; + /* Used for displaying pause on the screen */ + pause_label = [NSTextField new]; + [pause_label setBezeled:NO]; + [pause_label setDrawsBackground:YES]; + [pause_label setBackgroundColor: [NSColor yellowColor]]; + [pause_label setEditable:NO]; + [pause_label setSelectable:NO]; + [pause_label setStringValue: @"Paused"]; + [pause_label setFont: [NSFont fontWithName: @"Helvetica" size: 90]]; + [pause_label setTextColor: [NSColor redColor]]; + [pause_label sizeToFit]; + + /* Verify with the user before quitting QEMU */ + NSButton *closeButton = [normalWindow standardWindowButton:NSWindowCloseButton]; + [closeButton setTarget: self]; + [closeButton setAction: @selector(verifyQuit:)]; } return self; } @@ -943,6 +1063,119 @@ QemuCocoaView *cocoaView; [[NSWorkspace sharedWorkspace] openFile:[NSString stringWithFormat:@"%@/../doc/qemu/qemu-tech.html", [[NSBundle mainBundle] resourcePath]] withApplication:@"Help Viewer"]; } + +/* Pause the guest */ +- (void)pauseQemu:(id)sender +{ + qmp_stop(NULL); + [sender setEnabled: NO]; + [[[sender menu] itemWithTitle: @"Resume"] setEnabled: YES]; + [self displayPause]; +} + +/* Resume running the guest operating system */ +- (void)resumeQemu: (id) sender +{ + qmp_cont(NULL); + [sender setEnabled: NO]; + [[[sender menu] itemWithTitle: @"Pause"] setEnabled: YES]; + [self removePause]; +} + +/* Eject the floppy0 disk */ +- (void)ejectFloppy:(id)sender +{ + Error *err = NULL; + qmp_eject(floppy_drive_name, false, false, &err); + handleAnyDeviceErrors(err); +} + +/* Displays a dialog box asking the user to select a floppy image to load */ +- (void)changeFloppy:(id)sender +{ + NSOpenPanel * open_panel; + open_panel = [NSOpenPanel openPanel]; + [open_panel setCanChooseFiles: YES]; + [open_panel setAllowsMultipleSelection: NO]; + if([open_panel runModalForDirectory: nil file: nil] == NSOKButton) { + Error *err = NULL; + NSString * file = [[open_panel filenames] objectAtIndex: 0]; + qmp_change_blockdev(floppy_drive_name, [file cStringUsingEncoding: NSASCIIStringEncoding], "raw", &err); + handleAnyDeviceErrors(err); + } +} + +// Ejects the cdrom +- (void)ejectCdrom:(id)sender +{ + Error *err = NULL; + qmp_eject(cdrom_drive_name, false, false, &err); + handleAnyDeviceErrors(err); +} + +/* Displays a dialog box asking the user to select a CD image to load */ +- (void)changeCdrom:(id)sender +{ + NSOpenPanel * open_panel; + open_panel = [NSOpenPanel openPanel]; + [open_panel setCanChooseFiles: YES]; + [open_panel setAllowsMultipleSelection: NO]; + if([open_panel runModalForDirectory: nil file: nil] == NSOKButton) { + NSString * file = [[open_panel filenames] objectAtIndex: 0]; + Error *err = NULL; + qmp_change_blockdev(cdrom_drive_name, [file cStringUsingEncoding: NSASCIIStringEncoding], "raw", &err); + handleAnyDeviceErrors(err); + } +} + +/* Restarts QEMU */ +- (void)restartQemu:(id)sender +{ + qemu_system_reset_request(); +} + +/* Switches QEMU to use the real cdrom drive */ +- (void)useRealCdrom:(id)sender +{ + Error *err = NULL; + qmp_change_blockdev(cdrom_drive_name, "/dev/cdrom", "raw", &err); + handleAnyDeviceErrors(err); +} + +/* Verifies if the user really wants to quit */ +- (void)verifyQuit:(id)sender +{ + NSInteger response; + response = NSRunAlertPanel(@"Quit?", @"Are you sure you want to quit?", @"Cancel", @"Quit", nil); + if(response == NSAlertAlternateReturn) + qmp_quit(NULL); +} + +/* Powers down the emulator */ +- (void)powerDown:(id)sender +{ + qmp_system_powerdown(NULL); +} + +/* Displays the word pause on the screen */ +- (void)displayPause +{ + /* Coordinates have to be calculated each time because the window can change its size */ + int xCoord, yCoord, width, height; + xCoord = ([normalWindow frame].size.width - [pause_label frame].size.width)/2; + yCoord = [normalWindow frame].size.height - [pause_label frame].size.height - ([pause_label frame].size.height * .5); + width = [pause_label frame].size.width; + height = [pause_label frame].size.height; + [pause_label setFrame: NSMakeRect(xCoord, yCoord, width, height)]; + [cocoaView addSubview: pause_label]; +} + +/* Removes the word pause from the screen */ +- (void)removePause +{ + [pause_label removeFromSuperview]; +} + @end @@ -997,7 +1230,7 @@ int main (int argc, const char * argv[]) { [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)]; [menu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; // Show All [menu addItem:[NSMenuItem separatorItem]]; //Separator - [menu addItemWithTitle:@"Quit QEMU" action:@selector(terminate:) keyEquivalent:@"q"]; + [menu addItemWithTitle:@"Quit QEMU" action:@selector(verifyQuit:) keyEquivalent:@"q"]; menuItem = [[NSMenuItem alloc] initWithTitle:@"Apple" action:nil keyEquivalent:@""]; [menuItem setSubmenu:menu]; [[NSApp mainMenu] addItem:menuItem]; @@ -1128,4 +1361,7 @@ void cocoa_display_init(DisplayState *ds, int full_screen) // register cleanup function atexit(cocoa_cleanup); + + /* Creates and adds the Machine menu to the menubar */ + createMachineMenu(); } -- 1.7.5.4