From e251b5876383cac918b2cd03be034a5d24310b87 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Mon, 8 Mar 2021 23:07:13 +0900 Subject: [PATCH 1/8] ui/gtk: Remove NULL checks in gd_switch c821a58ee7 ("ui/console: Pass placeholder surface to display") eliminated the possibility that NULL is passed as surface to dpy_gfx_switch and removed some NULL checks from gd_switch, but the removal was not thoroughly. Remaining NULL checks were confusing for Coverity and probably also for humans. This change removes those NULL checks. Reported-by: Coverity (CID 1448421) Signed-off-by: Akihiko Odaki Reviewed-by: Peter Maydell Message-Id: <20210308140713.17901-1-akihiko.odaki@gmail.com> Signed-off-by: Gerd Hoffmann --- ui/gtk.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ui/gtk.c b/ui/gtk.c index 3edaf041de..eb1c9658e2 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -547,9 +547,7 @@ static void gd_switch(DisplayChangeListener *dcl, VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); bool resized = true; - trace_gd_switch(vc->label, - surface ? surface_width(surface) : 0, - surface ? surface_height(surface) : 0); + trace_gd_switch(vc->label, surface_width(surface), surface_height(surface)); if (vc->gfx.surface) { cairo_surface_destroy(vc->gfx.surface); @@ -560,7 +558,7 @@ static void gd_switch(DisplayChangeListener *dcl, vc->gfx.convert = NULL; } - if (vc->gfx.ds && surface && + if (vc->gfx.ds && surface_width(vc->gfx.ds) == surface_width(surface) && surface_height(vc->gfx.ds) == surface_height(surface)) { resized = false; From ae57d35cf0edc8f789d1d402f7494fbd7f3c07c5 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Fri, 5 Mar 2021 21:13:04 +0900 Subject: [PATCH 2/8] ui/cocoa: Use kCGColorSpaceSRGB kCGColorSpaceGenericRGB | Apple Developer Documentation https://developer.apple.com/documentation/coregraphics/kcgcolorspacegenericrgb > Deprecated > Use kCGColorSpaceSRGB instead. This change also removes the legacy color space specification for PowerPC. Signed-off-by: Akihiko Odaki Message-Id: <20210305121304.65096-1-akihiko.odaki@gmail.com> Signed-off-by: Gerd Hoffmann --- ui/cocoa.m | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/ui/cocoa.m b/ui/cocoa.m index f27beb30e6..3e1a7b7d51 100644 --- a/ui/cocoa.m +++ b/ui/cocoa.m @@ -463,13 +463,8 @@ QemuCocoaView *cocoaView; DIV_ROUND_UP(bitsPerPixel, 8) * 2, //bitsPerComponent bitsPerPixel, //bitsPerPixel stride, //bytesPerRow -#ifdef __LITTLE_ENDIAN__ - CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB), //colorspace for OS X >= 10.4 - kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst, -#else - CGColorSpaceCreateDeviceRGB(), //colorspace for OS X < 10.4 (actually ppc) - kCGImageAlphaNoneSkipFirst, //bitmapInfo -#endif + CGColorSpaceCreateWithName(kCGColorSpaceSRGB), //colorspace + kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst, //bitmapInfo dataProviderRef, //provider NULL, //decode 0, //interpolate From e26804031d772670a8901c24599cda323719e6f9 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 10 Mar 2021 05:58:21 +0100 Subject: [PATCH 3/8] docs: Fix removal text of -show-cursor We should say now when it was removed, not when it was deprecated. Signed-off-by: Thomas Huth Reviewed-by: Markus Armbruster Message-Id: <20210310045821.1004396-1-thuth@redhat.com> Signed-off-by: Gerd Hoffmann --- docs/system/removed-features.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/system/removed-features.rst b/docs/system/removed-features.rst index 4dcf4f924c..83148dcfda 100644 --- a/docs/system/removed-features.rst +++ b/docs/system/removed-features.rst @@ -26,8 +26,8 @@ The ``-no-kvm`` argument was a synonym for setting ``-machine accel=tcg``. The ``-realtime mlock=on|off`` argument has been replaced by the ``-overcommit mem-lock=on|off`` argument. -``-show-cursor`` option (since 5.0) -''''''''''''''''''''''''''''''''''' +``-show-cursor`` option (removed in 6.0) +'''''''''''''''''''''''''''''''''''''''' Use ``-display sdl,show-cursor=on``, ``-display gtk,show-cursor=on`` or ``-display default,show-cursor=on`` instead. From e31746ecf8dd2f25f687c94ac14016a3ba5debfc Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 9 Mar 2021 21:22:25 +0900 Subject: [PATCH 4/8] ui/cocoa: Show QEMU icon in the about window Signed-off-by: Akihiko Odaki Message-Id: <20210309122226.23117-1-akihiko.odaki@gmail.com> Signed-off-by: Gerd Hoffmann --- ui/cocoa.m | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/ui/cocoa.m b/ui/cocoa.m index 3e1a7b7d51..e589534fa4 100644 --- a/ui/cocoa.m +++ b/ui/cocoa.m @@ -39,6 +39,7 @@ #include "qapi/qapi-commands-misc.h" #include "sysemu/blockdev.h" #include "qemu-version.h" +#include "qemu/cutils.h" #include "qemu/main-loop.h" #include "qemu/module.h" #include @@ -1385,18 +1386,13 @@ QemuCocoaView *cocoaView; y = about_height - picture_height - 10; NSRect picture_rect = NSMakeRect(x, y, picture_width, picture_height); - /* Get the path to the QEMU binary */ - NSString *binary_name = [NSString stringWithCString: gArgv[0] - encoding: NSASCIIStringEncoding]; - binary_name = [binary_name lastPathComponent]; - NSString *program_path = [[NSString alloc] initWithFormat: @"%@/%@", - [[NSBundle mainBundle] bundlePath], binary_name]; - /* Make the picture of QEMU */ NSImageView *picture_view = [[NSImageView alloc] initWithFrame: picture_rect]; - NSImage *qemu_image = [[NSWorkspace sharedWorkspace] iconForFile: - program_path]; + char *qemu_image_path_c = get_relocated_path(CONFIG_QEMU_ICONDIR "/hicolor/512x512/apps/qemu.png"); + NSString *qemu_image_path = [NSString stringWithUTF8String:qemu_image_path_c]; + g_free(qemu_image_path_c); + NSImage *qemu_image = [[NSImage alloc] initWithContentsOfFile:qemu_image_path]; [picture_view setImage: qemu_image]; [picture_view setImageScaling: NSImageScaleProportionallyUpOrDown]; [superView addSubview: picture_view]; From a0f973f931680ae8bd847054aca7f658abb9c18f Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 9 Mar 2021 21:22:26 +0900 Subject: [PATCH 5/8] ui/cocoa: Do not rely on the first argument The first argument of the executable was used to get its path, but it is not reliable because the executer can specify any arbitrary string. Use the interfaces provided by QEMU and the platform to get those paths. Signed-off-by: Akihiko Odaki Message-Id: <20210309122226.23117-2-akihiko.odaki@gmail.com> Signed-off-by: Gerd Hoffmann --- ui/cocoa.m | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/ui/cocoa.m b/ui/cocoa.m index e589534fa4..4753bb2f88 100644 --- a/ui/cocoa.m +++ b/ui/cocoa.m @@ -1398,20 +1398,21 @@ QemuCocoaView *cocoaView; [superView addSubview: picture_view]; /* Make the name label */ - x = 0; - y = y - 25; - int name_width = about_width, name_height = 20; - NSRect name_rect = NSMakeRect(x, y, name_width, name_height); - NSTextField *name_label = [[NSTextField alloc] initWithFrame: name_rect]; - [name_label setEditable: NO]; - [name_label setBezeled: NO]; - [name_label setDrawsBackground: NO]; - [name_label setAlignment: NSTextAlignmentCenter]; - NSString *qemu_name = [[NSString alloc] initWithCString: gArgv[0] - encoding: NSASCIIStringEncoding]; - qemu_name = [qemu_name lastPathComponent]; - [name_label setStringValue: qemu_name]; - [superView addSubview: name_label]; + NSBundle *bundle = [NSBundle mainBundle]; + if (bundle) { + x = 0; + y = y - 25; + int name_width = about_width, name_height = 20; + NSRect name_rect = NSMakeRect(x, y, name_width, name_height); + NSTextField *name_label = [[NSTextField alloc] initWithFrame: name_rect]; + [name_label setEditable: NO]; + [name_label setBezeled: NO]; + [name_label setDrawsBackground: NO]; + [name_label setAlignment: NSTextAlignmentCenter]; + NSString *qemu_name = [[bundle executablePath] lastPathComponent]; + [name_label setStringValue: qemu_name]; + [superView addSubview: name_label]; + } /* Set the version label's attributes */ x = 0; From 6d73bb643aa725348aabe6a885ac5fb0b7f70252 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Wed, 10 Mar 2021 23:46:02 +0900 Subject: [PATCH 6/8] ui/cocoa: Clear modifiers whenever possible ui/cocoa does not receive NSEventTypeFlagsChanged when it is not active, and the modifier state can be desynchronized in such a situation. [NSEvent -modifierFlags] tells whether a modifier is *not* pressed, so check it whenever receiving an event and clear the modifier if it is not pressed. Note that [NSEvent -modifierFlags] does not tell if a certain modifier *is* pressed because the documented mask for [NSEvent -modifierFlags] generalizes left shift and right shift, for example. CapsLock is the only exception. The pressed state is synchronized only with NSEventTypeFlagsChanged. This change also removes modifier keys from keycode map. If they are input with NSEventTypeKeyDown or NSEventTypeKeyUp, it leads to desynchronization. Although such a situation is not observed, they are removed just in case. Moreover, QKbdState is introduced for automatic key state tracking. Thanks to Konstantin Nazarov for testing and finding a bug in this change: https://gist.github.com/akihikodaki/87df4149e7ca87f18dc56807ec5a1bc5#gistcomment-3659419 Signed-off-by: Akihiko Odaki Message-Id: <20210310144602.58528-1-akihiko.odaki@gmail.com> Signed-off-by: Gerd Hoffmann --- ui/cocoa.m | 152 +++++++++++++++++++++++++++-------------------------- 1 file changed, 78 insertions(+), 74 deletions(-) diff --git a/ui/cocoa.m b/ui/cocoa.m index 4753bb2f88..f71c59711f 100644 --- a/ui/cocoa.m +++ b/ui/cocoa.m @@ -30,6 +30,7 @@ #include "qemu-common.h" #include "ui/console.h" #include "ui/input.h" +#include "ui/kbd-state.h" #include "sysemu/sysemu.h" #include "sysemu/runstate.h" #include "sysemu/cpu-throttle.h" @@ -190,14 +191,6 @@ const int mac_to_qkeycode_map[] = { [kVK_ANSI_Comma] = Q_KEY_CODE_COMMA, [kVK_ANSI_Period] = Q_KEY_CODE_DOT, [kVK_ANSI_Slash] = Q_KEY_CODE_SLASH, - [kVK_Shift] = Q_KEY_CODE_SHIFT, - [kVK_RightShift] = Q_KEY_CODE_SHIFT_R, - [kVK_Control] = Q_KEY_CODE_CTRL, - [kVK_RightControl] = Q_KEY_CODE_CTRL_R, - [kVK_Option] = Q_KEY_CODE_ALT, - [kVK_RightOption] = Q_KEY_CODE_ALT_R, - [kVK_Command] = Q_KEY_CODE_META_L, - [0x36] = Q_KEY_CODE_META_R, /* There is no kVK_RightCommand */ [kVK_Space] = Q_KEY_CODE_SPC, [kVK_ANSI_Keypad0] = Q_KEY_CODE_KP_0, @@ -307,7 +300,7 @@ static void handleAnyDeviceErrors(Error * err) NSWindow *fullScreenWindow; float cx,cy,cw,ch,cdx,cdy; pixman_image_t *pixman_image; - BOOL modifiers_state[256]; + QKbdState *kbd; BOOL isMouseGrabbed; BOOL isFullscreen; BOOL isAbsoluteEnabled; @@ -354,6 +347,7 @@ QemuCocoaView *cocoaView; screen.width = frameRect.size.width; screen.height = frameRect.size.height; + kbd = qkbd_state_init(dcl.con); } return self; @@ -367,6 +361,7 @@ QemuCocoaView *cocoaView; pixman_image_unref(pixman_image); } + qkbd_state_free(kbd); [super dealloc]; } @@ -604,19 +599,8 @@ QemuCocoaView *cocoaView; } } -- (void) toggleModifier: (int)keycode { - // Toggle the stored state. - modifiers_state[keycode] = !modifiers_state[keycode]; - // Send a keyup or keydown depending on the state. - qemu_input_event_send_key_qcode(dcl.con, keycode, modifiers_state[keycode]); -} - -- (void) toggleStatefulModifier: (int)keycode { - // Toggle the stored state. - modifiers_state[keycode] = !modifiers_state[keycode]; - // Generate keydown and keyup. - qemu_input_event_send_key_qcode(dcl.con, keycode, true); - qemu_input_event_send_key_qcode(dcl.con, keycode, false); +- (void) toggleKey: (int)keycode { + qkbd_state_key_event(kbd, keycode, !qkbd_state_key_get(kbd, keycode)); } // Does the work of sending input to the monitor @@ -710,57 +694,86 @@ QemuCocoaView *cocoaView; static bool switched_to_fullscreen = false; // Location of event in virtual screen coordinates NSPoint p = [self screenLocationOfEvent:event]; + NSUInteger modifiers = [event modifierFlags]; + + // emulate caps lock keydown and keyup + if (!!(modifiers & NSEventModifierFlagCapsLock) != + qkbd_state_modifier_get(kbd, QKBD_MOD_CAPSLOCK)) { + qkbd_state_key_event(kbd, Q_KEY_CODE_CAPS_LOCK, true); + qkbd_state_key_event(kbd, Q_KEY_CODE_CAPS_LOCK, false); + } + + if (!(modifiers & NSEventModifierFlagShift)) { + qkbd_state_key_event(kbd, Q_KEY_CODE_SHIFT, false); + qkbd_state_key_event(kbd, Q_KEY_CODE_SHIFT_R, false); + } + if (!(modifiers & NSEventModifierFlagControl)) { + qkbd_state_key_event(kbd, Q_KEY_CODE_CTRL, false); + qkbd_state_key_event(kbd, Q_KEY_CODE_CTRL_R, false); + } + if (!(modifiers & NSEventModifierFlagOption)) { + qkbd_state_key_event(kbd, Q_KEY_CODE_ALT, false); + qkbd_state_key_event(kbd, Q_KEY_CODE_ALT_R, false); + } + if (!(modifiers & NSEventModifierFlagCommand)) { + qkbd_state_key_event(kbd, Q_KEY_CODE_META_L, false); + qkbd_state_key_event(kbd, Q_KEY_CODE_META_R, false); + } switch ([event type]) { case NSEventTypeFlagsChanged: - if ([event keyCode] == 0) { - // When the Cocoa keyCode is zero that means keys should be - // synthesized based on the values in in the eventModifiers - // bitmask. + switch ([event keyCode]) { + case kVK_Shift: + if (!!(modifiers & NSEventModifierFlagShift)) { + [self toggleKey:Q_KEY_CODE_SHIFT]; + } + break; - if (qemu_console_is_graphic(NULL)) { - NSUInteger modifiers = [event modifierFlags]; + case kVK_RightShift: + if (!!(modifiers & NSEventModifierFlagShift)) { + [self toggleKey:Q_KEY_CODE_SHIFT_R]; + } + break; - if (!!(modifiers & NSEventModifierFlagCapsLock) != !!modifiers_state[Q_KEY_CODE_CAPS_LOCK]) { - [self toggleStatefulModifier:Q_KEY_CODE_CAPS_LOCK]; + case kVK_Control: + if (!!(modifiers & NSEventModifierFlagControl)) { + [self toggleKey:Q_KEY_CODE_CTRL]; } - if (!!(modifiers & NSEventModifierFlagShift) != !!modifiers_state[Q_KEY_CODE_SHIFT]) { - [self toggleModifier:Q_KEY_CODE_SHIFT]; + break; + + case kVK_RightControl: + if (!!(modifiers & NSEventModifierFlagControl)) { + [self toggleKey:Q_KEY_CODE_CTRL_R]; } - if (!!(modifiers & NSEventModifierFlagControl) != !!modifiers_state[Q_KEY_CODE_CTRL]) { - [self toggleModifier:Q_KEY_CODE_CTRL]; + break; + + case kVK_Option: + if (!!(modifiers & NSEventModifierFlagOption)) { + [self toggleKey:Q_KEY_CODE_ALT]; } - if (!!(modifiers & NSEventModifierFlagOption) != !!modifiers_state[Q_KEY_CODE_ALT]) { - [self toggleModifier:Q_KEY_CODE_ALT]; + break; + + case kVK_RightOption: + if (!!(modifiers & NSEventModifierFlagOption)) { + [self toggleKey:Q_KEY_CODE_ALT_R]; } - if (!!(modifiers & NSEventModifierFlagCommand) != !!modifiers_state[Q_KEY_CODE_META_L]) { - [self toggleModifier:Q_KEY_CODE_META_L]; + break; + + /* Don't pass command key changes to guest unless mouse is grabbed */ + case kVK_Command: + if (isMouseGrabbed && + !!(modifiers & NSEventModifierFlagCommand)) { + [self toggleKey:Q_KEY_CODE_META_L]; } - } - } else { - keycode = cocoa_keycode_to_qemu([event keyCode]); + break; + + case kVK_RightCommand: + if (isMouseGrabbed && + !!(modifiers & NSEventModifierFlagCommand)) { + [self toggleKey:Q_KEY_CODE_META_R]; + } + break; } - - if ((keycode == Q_KEY_CODE_META_L || keycode == Q_KEY_CODE_META_R) - && !isMouseGrabbed) { - /* Don't pass command key changes to guest unless mouse is grabbed */ - keycode = 0; - } - - if (keycode) { - // emulate caps lock and num lock keydown and keyup - if (keycode == Q_KEY_CODE_CAPS_LOCK || - keycode == Q_KEY_CODE_NUM_LOCK) { - [self toggleStatefulModifier:keycode]; - } else if (qemu_console_is_graphic(NULL)) { - if (switched_to_fullscreen) { - switched_to_fullscreen = false; - } else { - [self toggleModifier:keycode]; - } - } - } - break; case NSEventTypeKeyDown: keycode = cocoa_keycode_to_qemu([event keyCode]); @@ -800,7 +813,7 @@ QemuCocoaView *cocoaView; } if (qemu_console_is_graphic(NULL)) { - qemu_input_event_send_key_qcode(dcl.con, keycode, true); + qkbd_state_key_event(kbd, keycode, true); } else { [self handleMonitorInput: event]; } @@ -815,7 +828,7 @@ QemuCocoaView *cocoaView; } if (qemu_console_is_graphic(NULL)) { - qemu_input_event_send_key_qcode(dcl.con, keycode, false); + qkbd_state_key_event(kbd, keycode, false); } break; case NSEventTypeMouseMoved: @@ -999,17 +1012,8 @@ QemuCocoaView *cocoaView; */ - (void) raiseAllKeys { - const int max_index = ARRAY_SIZE(modifiers_state); - with_iothread_lock(^{ - int index; - - for (index = 0; index < max_index; index++) { - if (modifiers_state[index]) { - modifiers_state[index] = 0; - qemu_input_event_send_key_qcode(dcl.con, index, false); - } - } + qkbd_state_lift_all_keys(kbd); }); } @end From cb82340825eed168f732511926477f5f124010be Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Thu, 25 Feb 2021 17:42:02 +0900 Subject: [PATCH 7/8] ui/cocoa: Mark variables static Signed-off-by: Akihiko Odaki Message-Id: <20210225084202.39601-1-akihiko.odaki@gmail.com> Signed-off-by: Gerd Hoffmann --- ui/cocoa.m | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ui/cocoa.m b/ui/cocoa.m index f71c59711f..3af167f071 100644 --- a/ui/cocoa.m +++ b/ui/cocoa.m @@ -82,7 +82,7 @@ static void cocoa_switch(DisplayChangeListener *dcl, static void cocoa_refresh(DisplayChangeListener *dcl); -NSWindow *normalWindow, *about_window; +static NSWindow *normalWindow, *about_window; static const DisplayChangeListenerOps dcl_ops = { .dpy_name = "cocoa", .dpy_gfx_update = cocoa_update, @@ -95,11 +95,11 @@ static DisplayChangeListener dcl = { static int last_buttons; static int cursor_hide = 1; -int gArgc; -char **gArgv; -bool stretch_video; -NSTextField *pauseLabel; -NSArray * supportedImageFileTypes; +static int gArgc; +static char **gArgv; +static bool stretch_video; +static NSTextField *pauseLabel; +static NSArray * supportedImageFileTypes; static QemuSemaphore display_init_sem; static QemuSemaphore app_started_sem; @@ -137,7 +137,7 @@ static bool bool_with_iothread_lock(BoolCodeBlock block) } // Mac to QKeyCode conversion -const int mac_to_qkeycode_map[] = { +static const int mac_to_qkeycode_map[] = { [kVK_ANSI_A] = Q_KEY_CODE_A, [kVK_ANSI_B] = Q_KEY_CODE_B, [kVK_ANSI_C] = Q_KEY_CODE_C, From d1929069e355afb809a50a7f6b6affdea399cc8c Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 23 Feb 2021 00:07:14 +0900 Subject: [PATCH 8/8] ui/cocoa: Fix mouse association state ui/cocoa deassociates the mouse input and the mouse cursor position only when relative movement inputs are expected. Such inputs may let the mouse cursor leave the view and cause undesired side effects if they are associated. On the other hand, the problem does not occur when inputting absolute points, and the association allows seamless cursor movement across views. However, the synchronization of the association and the expected input type was only done when grabbing the mouse. In reality, the state whether the emulated input device expects absolute pointing inputs or relative movement inputs can vary dynamically due to USB device hot-plugging, for example. This change adds association state updates according to input type expectation changes. It also removes an internal flag representing the association state because the state can now be determined with the current input type expectation and it only adds the complexity of the state tracking. Signed-off-by: Akihiko Odaki Message-Id: <20210222150714.21766-1-akihiko.odaki@gmail.com> Signed-off-by: Gerd Hoffmann --- ui/cocoa.m | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/ui/cocoa.m b/ui/cocoa.m index 3af167f071..a7848ae0a3 100644 --- a/ui/cocoa.m +++ b/ui/cocoa.m @@ -304,7 +304,6 @@ static void handleAnyDeviceErrors(Error * err) BOOL isMouseGrabbed; BOOL isFullscreen; BOOL isAbsoluteEnabled; - BOOL isMouseDeassociated; } - (void) switchSurface:(pixman_image_t *)image; - (void) grabMouse; @@ -321,14 +320,9 @@ static void handleAnyDeviceErrors(Error * err) * isMouseGrabbed tracks whether GUI events are directed to the guest; * it controls whether special keys like Cmd get sent to the guest, * and whether we capture the mouse when in non-absolute mode. - * isMouseDeassociated tracks whether we've told MacOSX to disassociate - * the mouse and mouse cursor position by calling - * CGAssociateMouseAndMouseCursorPosition(FALSE) - * (which basically happens if we grab in non-absolute mode). */ - (BOOL) isMouseGrabbed; - (BOOL) isAbsoluteEnabled; -- (BOOL) isMouseDeassociated; - (float) cdx; - (float) cdy; - (QEMUScreen) gscreen; @@ -972,10 +966,7 @@ QemuCocoaView *cocoaView; [normalWindow setTitle:@"QEMU - (Press ctrl + alt + g to release Mouse)"]; } [self hideCursor]; - if (!isAbsoluteEnabled) { - isMouseDeassociated = TRUE; - CGAssociateMouseAndMouseCursorPosition(FALSE); - } + CGAssociateMouseAndMouseCursorPosition(isAbsoluteEnabled); isMouseGrabbed = TRUE; // while isMouseGrabbed = TRUE, QemuCocoaApp sends all events to [cocoaView handleEvent:] } @@ -990,17 +981,18 @@ QemuCocoaView *cocoaView; [normalWindow setTitle:@"QEMU"]; } [self unhideCursor]; - if (isMouseDeassociated) { - CGAssociateMouseAndMouseCursorPosition(TRUE); - isMouseDeassociated = FALSE; - } + CGAssociateMouseAndMouseCursorPosition(TRUE); isMouseGrabbed = FALSE; } -- (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled {isAbsoluteEnabled = tIsAbsoluteEnabled;} +- (void) setAbsoluteEnabled:(BOOL)tIsAbsoluteEnabled { + isAbsoluteEnabled = tIsAbsoluteEnabled; + if (isMouseGrabbed) { + CGAssociateMouseAndMouseCursorPosition(isAbsoluteEnabled); + } +} - (BOOL) isMouseGrabbed {return isMouseGrabbed;} - (BOOL) isAbsoluteEnabled {return isAbsoluteEnabled;} -- (BOOL) isMouseDeassociated {return isMouseDeassociated;} - (float) cdx {return cdx;} - (float) cdy {return cdy;} - (QEMUScreen) gscreen {return screen;}