+}
+
+- (void) resizeWindow
+{
+ [[self window] setContentAspectRatio:NSMakeSize(screen.width,
screen.height)];
+
+ if (([[self window] styleMask] & NSWindowStyleMaskResizable) == 0) {
+ [[self window] setContentSize:NSMakeSize(screen.width, screen.height)];
+ [[self window] center];
+ } else if (([[self window] styleMask] & NSWindowStyleMaskFullScreen) != 0)
{
+ [[self window] setContentSize:[self fixZoomedFullScreenSize:[[[self
window] screen] frame].size]];
+ [[self window] center];
}
}
@@ -538,7 +527,12 @@ - (void) updateUIInfo
NSSize screenSize = [[[self window] screen] frame].size;
CGSize screenPhysicalSize = CGDisplayScreenSize(display);
- frameSize = isFullscreen ? screenSize : [self frame].size;
+ if (([[self window] styleMask] & NSWindowStyleMaskFullScreen) == 0) {
+ frameSize = [self frame].size;
+ } else {
+ frameSize = screenSize;
+ }
+
info.width_mm = frameSize.width / screenSize.width *
screenPhysicalSize.width;
info.height_mm = frameSize.height / screenSize.height *
screenPhysicalSize.height;
} else {
@@ -555,31 +549,19 @@ - (void) updateUIInfo
dpy_set_ui_info(dcl.con, &info);
}
-- (void)viewDidMoveToWindow
-{
- [self updateUIInfo];
-}
-
- (void) switchSurface:(pixman_image_t *)image
{
COCOA_DEBUG("QemuCocoaView: switchSurface\n");
int w = pixman_image_get_width(image);
int h = pixman_image_get_height(image);
- /* cdx == 0 means this is our very first surface, in which case we need
- * to recalculate the content dimensions even if it happens to be the size
- * of the initial empty window.
- */
- bool isResize = (w != screen.width || h != screen.height || cdx == 0.0);
- int oldh = screen.height;
- if (isResize) {
+ if (w != screen.width || h != screen.height) {
// Resize before we trigger the redraw, or we'll redraw at the wrong
size
COCOA_DEBUG("switchSurface: new size %d x %d\n", w, h);
screen.width = w;
screen.height = h;
- [self setContentDimensions];
- [self setFrame:NSMakeRect(cx, cy, cw, ch)];
+ [self resizeWindow];
}
// update screenBuffer
@@ -588,51 +570,6 @@ - (void) switchSurface:(pixman_image_t *)image
}
pixman_image = image;
-
- // update windows
- if (isFullscreen) {
- [[fullScreenWindow contentView] setFrame:[[NSScreen mainScreen]
frame]];
- [normalWindow setFrame:NSMakeRect([normalWindow frame].origin.x,
[normalWindow frame].origin.y - h + oldh, w, h + [normalWindow
frame].size.height - oldh) display:NO animate:NO];
- } else {
- if (qemu_name)
- [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s",
qemu_name]];
- [normalWindow setFrame:NSMakeRect([normalWindow frame].origin.x,
[normalWindow frame].origin.y - h + oldh, w, h + [normalWindow
frame].size.height - oldh) display:YES animate:NO];
- }
-
- if (isResize) {
- [normalWindow center];
- }
-}
-
-- (void) toggleFullScreen:(id)sender
-{
- COCOA_DEBUG("QemuCocoaView: toggleFullScreen\n");
-
- if (isFullscreen) { // switch from fullscreen to desktop
- isFullscreen = FALSE;
- [self ungrabMouse];
- [self setContentDimensions];
- [fullScreenWindow close];
- [normalWindow setContentView: self];
- [normalWindow makeKeyAndOrderFront: self];
- [NSMenu setMenuBarVisible:YES];
- } else { // switch from desktop to fullscreen
- isFullscreen = TRUE;
- [normalWindow orderOut: nil]; /* Hide the window */
- [self grabMouse];
- [self setContentDimensions];
- [NSMenu setMenuBarVisible:NO];
- fullScreenWindow = [[NSWindow alloc] initWithContentRect:[[NSScreen
mainScreen] frame]
- styleMask:NSWindowStyleMaskBorderless
- backing:NSBackingStoreBuffered
- defer:NO];
- [fullScreenWindow setAcceptsMouseMovedEvents: YES];
- [fullScreenWindow setHasShadow:NO];
- [fullScreenWindow setBackgroundColor: [NSColor blackColor]];
- [self setFrame:NSMakeRect(cx, cy, cw, ch)];
- [[fullScreenWindow contentView] addSubview: self];
- [fullScreenWindow makeKeyAndOrderFront:self];
- }
}
- (void) toggleKey: (int)keycode {
@@ -724,12 +661,7 @@ - (bool) handleEventLocked:(NSEvent *)event
{
/* Return true if we handled the event, false if it should be given to OSX
*/
COCOA_DEBUG("QemuCocoaView: handleEvent\n");
- int buttons = 0;
int keycode = 0;
- bool mouse_event = false;
- static bool switched_to_fullscreen = false;
- // Location of event in virtual screen coordinates
- NSPoint p = [self screenLocationOfEvent:event];
NSUInteger modifiers = [event modifierFlags];
/*
@@ -799,37 +731,37 @@ - (bool) handleEventLocked:(NSEvent *)event
if (!!(modifiers & NSEventModifierFlagShift)) {
[self toggleKey:Q_KEY_CODE_SHIFT];
}
- break;
+ return true;
case kVK_RightShift:
if (!!(modifiers & NSEventModifierFlagShift)) {
[self toggleKey:Q_KEY_CODE_SHIFT_R];
}
- break;
+ return true;
case kVK_Control:
if (!!(modifiers & NSEventModifierFlagControl)) {
[self toggleKey:Q_KEY_CODE_CTRL];
}
- break;
+ return true;
case kVK_RightControl:
if (!!(modifiers & NSEventModifierFlagControl)) {
[self toggleKey:Q_KEY_CODE_CTRL_R];
}
- break;
+ return true;
case kVK_Option:
if (!!(modifiers & NSEventModifierFlagOption)) {
[self toggleKey:Q_KEY_CODE_ALT];
}
- break;
+ return true;
case kVK_RightOption:
if (!!(modifiers & NSEventModifierFlagOption)) {
[self toggleKey:Q_KEY_CODE_ALT_R];
}
- break;
+ return true;
/* Don't pass command key changes to guest unless mouse is
grabbed */
case kVK_Command:
@@ -837,28 +769,23 @@ - (bool) handleEventLocked:(NSEvent *)event
!!(modifiers & NSEventModifierFlagCommand)) {
[self toggleKey:Q_KEY_CODE_META_L];
}
- break;
+ return true;
case kVK_RightCommand:
if (isMouseGrabbed &&
!!(modifiers & NSEventModifierFlagCommand)) {
[self toggleKey:Q_KEY_CODE_META_R];
}
- break;
+ return true;
+
+ default:
+ return true;
}
- break;
case NSEventTypeKeyDown:
keycode = cocoa_keycode_to_qemu([event keyCode]);
// forward command key combos to the host UI unless the mouse is
grabbed
if (!isMouseGrabbed && ([event modifierFlags] &
NSEventModifierFlagCommand)) {
- /*
- * Prevent the command key from being stuck down in the guest
- * when using Command-F to switch to full screen mode.
- */
- if (keycode == Q_KEY_CODE_F) {
- switched_to_fullscreen = true;
- }
return false;
}
@@ -889,7 +816,7 @@ - (bool) handleEventLocked:(NSEvent *)event
} else {
[self handleMonitorInput: event];
}
- break;
+ return true;
case NSEventTypeKeyUp:
keycode = cocoa_keycode_to_qemu([event keyCode]);
@@ -902,67 +829,7 @@ - (bool) handleEventLocked:(NSEvent *)event
if (qemu_console_is_graphic(NULL)) {
qkbd_state_key_event(kbd, keycode, false);
}
- break;
- case NSEventTypeMouseMoved:
- if (isAbsoluteEnabled) {
- // Cursor re-entered into a window might generate events bound
to screen coordinates
- // and `nil` window property, and in full screen mode, current
window might not be
- // key window, where event location alone should suffice.
- if (![self screenContainsPoint:p] || !([[self window]
isKeyWindow] || isFullscreen)) {
- if (isMouseGrabbed) {
- [self ungrabMouse];
- }
- } else {
- if (!isMouseGrabbed) {
- [self grabMouse];
- }
- }
- }
- mouse_event = true;
- break;
- case NSEventTypeLeftMouseDown:
- buttons |= MOUSE_EVENT_LBUTTON;
- mouse_event = true;
- break;
- case NSEventTypeRightMouseDown:
- buttons |= MOUSE_EVENT_RBUTTON;
- mouse_event = true;
- break;
- case NSEventTypeOtherMouseDown:
- buttons |= MOUSE_EVENT_MBUTTON;
- mouse_event = true;
- break;
- case NSEventTypeLeftMouseDragged:
- buttons |= MOUSE_EVENT_LBUTTON;
- mouse_event = true;
- break;
- case NSEventTypeRightMouseDragged:
- buttons |= MOUSE_EVENT_RBUTTON;
- mouse_event = true;
- break;
- case NSEventTypeOtherMouseDragged:
- buttons |= MOUSE_EVENT_MBUTTON;
- mouse_event = true;
- break;
- case NSEventTypeLeftMouseUp:
- mouse_event = true;
- if (!isMouseGrabbed && [self screenContainsPoint:p]) {
- /*
- * In fullscreen mode, the window of cocoaView may not be the
- * key window, therefore the position relative to the virtual
- * screen alone will be sufficient.
- */
- if(isFullscreen || [[self window] isKeyWindow]) {
- [self grabMouse];
- }
- }
- break;
- case NSEventTypeRightMouseUp:
- mouse_event = true;
- break;
- case NSEventTypeOtherMouseUp:
- mouse_event = true;
- break;
+ return true;
case NSEventTypeScrollWheel:
/*
* Send wheel events to the guest regardless of window focus.
@@ -976,7 +843,7 @@ - (bool) handleEventLocked:(NSEvent *)event
*/
if ([event deltaY] != 0) {
/* Determine if this is a scroll up or scroll down event */
- buttons = ([event deltaY] > 0) ?
+ int buttons = ([event deltaY] > 0) ?
INPUT_BUTTON_WHEEL_UP : INPUT_BUTTON_WHEEL_DOWN;
qemu_input_queue_btn(dcl.con, buttons, true);
qemu_input_event_sync();
@@ -987,62 +854,124 @@ - (bool) handleEventLocked:(NSEvent *)event
* Since deltaY also reports scroll wheel events we prevent mouse
* movement code from executing.
*/
- mouse_event = false;
- break;
+ return true;
default:
return false;
}
+}
- if (mouse_event) {
- /* Don't send button events to the guest unless we've got a
- * mouse grab or window focus. If we have neither then this event
- * is the user clicking on the background window to activate and
- * bring us to the front, which will be done by the sendEvent
- * call below. We definitely don't want to pass that click through
- * to the guest.
- */
- if ((isMouseGrabbed || [[self window] isKeyWindow]) &&
- (last_buttons != buttons)) {
- static uint32_t bmap[INPUT_BUTTON__MAX] = {
- [INPUT_BUTTON_LEFT] = MOUSE_EVENT_LBUTTON,
- [INPUT_BUTTON_MIDDLE] = MOUSE_EVENT_MBUTTON,
- [INPUT_BUTTON_RIGHT] = MOUSE_EVENT_RBUTTON
- };
- qemu_input_update_buttons(dcl.con, bmap, last_buttons, buttons);
- last_buttons = buttons;
- }
- if (isMouseGrabbed) {
- if (isAbsoluteEnabled) {
- /* Note that the origin for Cocoa mouse coords is bottom left,
not top left.
- * The check on screenContainsPoint is to avoid sending out of
range values for
- * clicks in the titlebar.
- */
- if ([self screenContainsPoint:p]) {
- qemu_input_queue_abs(dcl.con, INPUT_AXIS_X, p.x, 0,
screen.width);
- qemu_input_queue_abs(dcl.con, INPUT_AXIS_Y, screen.height
- p.y, 0, screen.height);
- }
- } else {
- qemu_input_queue_rel(dcl.con, INPUT_AXIS_X, (int)[event
deltaX]);
- qemu_input_queue_rel(dcl.con, INPUT_AXIS_Y, (int)[event
deltaY]);
- }
+- (void) handleMouseEvent:(NSEvent *)event
+{
+ if (!isMouseGrabbed) {
+ return;
+ }
+
+ with_iothread_lock(^{
+ if (isAbsoluteEnabled) {
+ CGFloat d = (CGFloat)screen.height / [self frame].size.height;
+ NSPoint p = [event locationInWindow];
+ // Note that the origin for Cocoa mouse coords is bottom left, not
top left.
+ qemu_input_queue_abs(dcl.con, INPUT_AXIS_X, p.x * d, 0,
screen.width);
+ qemu_input_queue_abs(dcl.con, INPUT_AXIS_Y, screen.height - p.y *
d, 0, screen.height);
} else {
- return false;
+ CGFloat d = (CGFloat)screen.height / [self
convertSizeToBacking:[self frame].size].height;
+ qemu_input_queue_rel(dcl.con, INPUT_AXIS_X, [event deltaX] * d);
+ qemu_input_queue_rel(dcl.con, INPUT_AXIS_Y, [event deltaY] * d);
}
+
qemu_input_event_sync();
+ });
+}
+
+- (void) handleMouseEvent:(NSEvent *)event button:(InputButton)button
down:(bool)down
+{
+ if (!isMouseGrabbed) {
+ return;
}
- return true;
+
+ with_iothread_lock(^{
+ qemu_input_queue_btn(dcl.con, button, down);
+ });
+
+ [self handleMouseEvent:event];
+}
+
+- (void) mouseExited:(NSEvent *)event
+{
+ if (isAbsoluteEnabled && isMouseGrabbed) {
+ [self ungrabMouse];
+ }
+}
+
+- (void) mouseEntered:(NSEvent *)event
+{
+ if (isAbsoluteEnabled && !isMouseGrabbed) {
+ [self grabMouse];
+ }
+}
+
+- (void) mouseMoved:(NSEvent *)event
+{
+ [self handleMouseEvent:event];
+}
+
+- (void) mouseDown:(NSEvent *)event
+{
+ [self handleMouseEvent:event button:INPUT_BUTTON_LEFT down:true];
+}
+
+- (void) rightMouseDown:(NSEvent *)event
+{
+ [self handleMouseEvent:event button:INPUT_BUTTON_RIGHT down:true];
+}
+
+- (void) otherMouseDown:(NSEvent *)event
+{
+ [self handleMouseEvent:event button:INPUT_BUTTON_MIDDLE down:true];
+}
+
+- (void) mouseDragged:(NSEvent *)event
+{
+ [self handleMouseEvent:event];
+}
+
+- (void) rightMouseDragged:(NSEvent *)event
+{
+ [self handleMouseEvent:event];
+}
+
+- (void) otherMouseDragged:(NSEvent *)event
+{
+ [self handleMouseEvent:event];
+}
+
+- (void) mouseUp:(NSEvent *)event
+{
+ if (!isMouseGrabbed) {
+ [self grabMouse];
+ }
+
+ [self handleMouseEvent:event button:INPUT_BUTTON_LEFT down:false];
+}
+
+- (void) rightMouseUp:(NSEvent *)event
+{
+ [self handleMouseEvent:event button:INPUT_BUTTON_RIGHT down:false];
+}
+
+- (void) otherMouseUp:(NSEvent *)event
+{
+ [self handleMouseEvent:event button:INPUT_BUTTON_MIDDLE down:false];
}
- (void) grabMouse
{
COCOA_DEBUG("QemuCocoaView: grabMouse\n");
- if (!isFullscreen) {
- if (qemu_name)
- [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s - (Press
ctrl + alt + g to release Mouse)", qemu_name]];
- else
- [normalWindow setTitle:@"QEMU - (Press ctrl + alt + g to release
Mouse)"];
- }
+ if (qemu_name)
+ [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s - (Press ctrl +
alt + g to release Mouse)", qemu_name]];
+ else
+ [normalWindow setTitle:@"QEMU - (Press ctrl + alt + g to release
Mouse)"];
[self hideCursor];
CGAssociateMouseAndMouseCursorPosition(isAbsoluteEnabled);
isMouseGrabbed = TRUE; // while isMouseGrabbed = TRUE, QemuCocoaApp sends
all events to [cocoaView handleEvent:]
@@ -1052,15 +981,14 @@ - (void) ungrabMouse
{
COCOA_DEBUG("QemuCocoaView: ungrabMouse\n");
- if (!isFullscreen) {
- if (qemu_name)
- [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s",
qemu_name]];
- else
- [normalWindow setTitle:@"QEMU"];
- }
+ if (qemu_name)
+ [normalWindow setTitle:[NSString stringWithFormat:@"QEMU %s",
qemu_name]];
+ else
+ [normalWindow setTitle:@"QEMU"];
[self unhideCursor];
CGAssociateMouseAndMouseCursorPosition(TRUE);
isMouseGrabbed = FALSE;
+ [self raiseAllButtons];
}
- (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled {
@@ -1071,8 +999,6 @@ - (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled {
}
- (BOOL) isMouseGrabbed {return isMouseGrabbed;}
- (BOOL) isAbsoluteEnabled {return isAbsoluteEnabled;}
-- (float) cdx {return cdx;}
-- (float) cdy {return cdy;}
- (QEMUScreen) gscreen {return screen;}
/*
@@ -1086,6 +1012,15 @@ - (void) raiseAllKeys
qkbd_state_lift_all_keys(kbd);
});
}
+
+- (void) raiseAllButtons
+{
+ with_iothread_lock(^{
+ qemu_input_queue_btn(dcl.con, INPUT_BUTTON_LEFT, false);
+ qemu_input_queue_btn(dcl.con, INPUT_BUTTON_RIGHT, false);
+ qemu_input_queue_btn(dcl.con, INPUT_BUTTON_MIDDLE, false);
+ });
+}
@end
@@ -1100,7 +1035,6 @@ @interface QemuCocoaAppController : NSObject
{
}
- (void)doToggleFullScreen:(id)sender;
-- (void)toggleFullScreen:(id)sender;
- (void)showQEMUDoc:(id)sender;
- (void)zoomToFit:(id) sender;
- (void)displayConsole:(id)sender;
@@ -1143,12 +1077,12 @@ - (id) init
exit(1);
}
[normalWindow setAcceptsMouseMovedEvents:YES];
- [normalWindow setTitle:@"QEMU"];
+ [normalWindow
setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
+ [normalWindow setTitle:qemu_name ? [NSString stringWithFormat:@"QEMU %s",
qemu_name] : @"QEMU"];
[normalWindow setContentView:cocoaView];
[normalWindow makeKeyAndOrderFront:self];
[normalWindow center];
[normalWindow setDelegate: self];
- stretch_video = false;
/* Used for displaying pause on the screen */
pauseLabel = [NSTextField new];
@@ -1219,9 +1153,20 @@ - (void)windowDidChangeScreen:(NSNotification
*)notification
[cocoaView updateUIInfo];
}
+- (void)windowDidEnterFullScreen:(NSNotification *)notification
+{
+ [cocoaView grabMouse];
+}
+
+- (void)windowDidExitFullScreen:(NSNotification *)notification
+{
+ [cocoaView resizeWindow];
+ [cocoaView ungrabMouse];
+}
+
- (void)windowDidResize:(NSNotification *)notification
{
- [cocoaView updateUIInfo];
+ [cocoaView frameUpdated];
}
/* Called when the user clicks on a window's close button */
@@ -1237,6 +1182,23 @@ - (BOOL)windowShouldClose:(id)sender
return NO;
}
+- (NSSize) window:(NSWindow *)window
willUseFullScreenContentSize:(NSSize)proposedSize
+{
+ if (([normalWindow styleMask] & NSWindowStyleMaskResizable) == 0) {
+ return NSMakeSize([cocoaView gscreen].width, [cocoaView
gscreen].height);
+ }
+
+ return [cocoaView fixZoomedFullScreenSize:proposedSize];
+}
+
+- (NSApplicationPresentationOptions) window:(NSWindow *)window
+
willUseFullScreenPresentationOptions:(NSApplicationPresentationOptions)proposedOptions;
+
+{
+ return (proposedOptions & ~(NSApplicationPresentationAutoHideDock |
NSApplicationPresentationAutoHideMenuBar)) |
+ NSApplicationPresentationHideDock |
NSApplicationPresentationHideMenuBar;