qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Phil Dennis-Jordan <phil@philjordan.eu>
To: qemu-devel@nongnu.org
Cc: peter.maydell@linaro.org, philmd@linaro.org,
	marcandre.lureau@redhat.com, akihiko.odaki@daynix.com,
	lists@philjordan.eu, Phil Dennis-Jordan <phil@philjordan.eu>
Subject: [PATCH v2 2/2] ui/cocoa: Adds NSCursor absolute pointer support
Date: Tue, 25 Jun 2024 15:49:31 +0200	[thread overview]
Message-ID: <20240625134931.92279-3-phil@philjordan.eu> (raw)
In-Reply-To: <20240625134931.92279-1-phil@philjordan.eu>

When pointer input is absolute, use the native macOS host’s Cocoa
NSCursor to render the guest’s cursor. The rendered cursor is no longer
cropped to the guest viewport, and the correct cursor image is passed to
anything tapping into the host system’s native cursor. (such as remote
access)

The CALayer is retained for rendering the cursor in relative pointer
input mode. Cropping the cursor here gives a visual indication of the
captured pointer (the mouse must be explicitly ungrabbed before allowing
the cursor to leave the Qemu window), and teleporting the host cursor
when its position is changed by the guest causes a feedback loop in
input events.

Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu>
---
 ui/cocoa.m | 82 +++++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 65 insertions(+), 17 deletions(-)

diff --git a/ui/cocoa.m b/ui/cocoa.m
index cca987eac7..131c442e16 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -314,6 +314,7 @@ @interface QemuCocoaView : NSView
     CFMachPortRef eventsTap;
     CALayer *cursorLayer;
     QEMUCursor *cursor;
+    NSCursor *cocoaCursor;
     int mouseX;
     int mouseY;
     int mouseOn;
@@ -402,6 +403,9 @@ - (void) dealloc
 
     [cursorLayer release];
     cursorLayer = nil;
+    [cocoaCursor release];
+    cocoaCursor = nil;
+
     [super dealloc];
 }
 
@@ -460,27 +464,14 @@ - (void)setMouseX:(int)x y:(int)y on:(int)on
     [CATransaction begin];
     [CATransaction setDisableActions:YES];
     [cursorLayer setPosition:position];
-    [cursorLayer setHidden:!mouseOn];
+    [cursorLayer setHidden:!mouseOn || isAbsoluteEnabled];
     [CATransaction commit];
 }
 
-- (void)setCursor:(QEMUCursor *)given_cursor
+static CGImageRef cursor_cgimage_create(QEMUCursor *cursor)
 {
     CGDataProviderRef provider;
     CGImageRef image;
-    CGRect bounds = CGRectZero;
-
-    cursor_unref(cursor);
-    cursor = given_cursor;
-
-    if (!cursor) {
-        return;
-    }
-
-    cursor_ref(cursor);
-
-    bounds.size.width = cursor->width;
-    bounds.size.height = cursor->height;
     CGColorSpaceRef color_space = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
 
     provider = CGDataProviderCreateWithData(
@@ -506,6 +497,43 @@ - (void)setCursor:(QEMUCursor *)given_cursor
 
     CGDataProviderRelease(provider);
     CGColorSpaceRelease(color_space);
+    return image;
+}
+
+static NSCursor *cocoa_cursor_create(QEMUCursor *cursor, CGImageRef image)
+{
+    NSPoint hotspot = { cursor->hot_x, cursor->hot_y };
+    NSSize size = NSMakeSize(cursor->width, cursor->height);
+    NSImage *cursor_image = [[NSImage alloc] initWithCGImage:image size:size];
+    NSCursor *cocoa_cursor =
+        [[NSCursor alloc] initWithImage:cursor_image hotSpot:hotspot];
+    [cursor_image release];
+    return cocoa_cursor;
+}
+
+- (void)setCursor:(QEMUCursor *)given_cursor
+{
+    CGImageRef image;
+    NSImage *cursor_nsimage = nil;
+    CGRect bounds = CGRectZero;
+
+    cursor_unref(cursor);
+    cursor = given_cursor;
+
+    if (!cursor) {
+        return;
+    }
+
+    cursor_ref(cursor);
+
+    bounds.size.width = cursor->width;
+    bounds.size.height = cursor->height;
+
+    image = cursor_cgimage_create(cursor);
+    [cocoaCursor release];
+    cocoaCursor = cocoa_cursor_create(cursor, image);
+    [self.window invalidateCursorRectsForView:self];
+
     [CATransaction begin];
     [CATransaction setDisableActions:YES];
     [cursorLayer setBounds:bounds];
@@ -514,6 +542,16 @@ - (void)setCursor:(QEMUCursor *)given_cursor
     CGImageRelease(image);
 }
 
+- (void) resetCursorRects
+{
+    if (self->cocoaCursor == nil) {
+        [super resetCursorRects];
+    } else {
+        NSRect guest_area = {{ 0.0, 0.0 }, { screen.width, screen.height }};
+        [self addCursorRect:guest_area cursor:cocoaCursor];
+    }
+}
+
 - (void) drawRect:(NSRect) rect
 {
     COCOA_DEBUG("QemuCocoaView: drawRect\n");
@@ -1181,7 +1219,12 @@ - (void) grabMouse
         [[self window] setTitle:[NSString stringWithFormat:@"QEMU %s - (Press  " UC_CTRL_KEY " " UC_ALT_KEY " G  to release Mouse)", qemu_name]];
     else
         [[self window] setTitle:@"QEMU - (Press  " UC_CTRL_KEY " " UC_ALT_KEY " G  to release Mouse)"];
-    [self hideCursor];
+
+    [cursorLayer setHidden:!mouseOn || isAbsoluteEnabled];
+    if (!isAbsoluteEnabled) {
+        [self hideCursor];
+    }
+
     CGAssociateMouseAndMouseCursorPosition(isAbsoluteEnabled);
     isMouseGrabbed = TRUE; // while isMouseGrabbed = TRUE, QemuCocoaApp sends all events to [cocoaView handleEvent:]
 }
@@ -1194,7 +1237,11 @@ - (void) ungrabMouse
         [[self window] setTitle:[NSString stringWithFormat:@"QEMU %s", qemu_name]];
     else
         [[self window] setTitle:@"QEMU"];
-    [self unhideCursor];
+
+    [cursorLayer setHidden:!mouseOn || isAbsoluteEnabled];
+    if (!isAbsoluteEnabled) {
+        [self unhideCursor];
+    }
     CGAssociateMouseAndMouseCursorPosition(TRUE);
     isMouseGrabbed = FALSE;
     [self raiseAllButtons];
@@ -1216,6 +1263,7 @@ - (void) notifyMouseModeChange {
             [self ungrabMouse];
         } else {
             CGAssociateMouseAndMouseCursorPosition(isAbsoluteEnabled);
+            [self hideCursor];
         }
     }
 }
-- 
2.39.3 (Apple Git-146)



  parent reply	other threads:[~2024-06-25 13:50 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-06-25 13:49 [PATCH v2 0/2] ui/cocoa: Adds native absolute pointer support Phil Dennis-Jordan
2024-06-25 13:49 ` [PATCH v2 1/2] ui/cocoa: Minor fixes to CALayer based cursors Phil Dennis-Jordan
2024-06-25 13:49 ` Phil Dennis-Jordan [this message]
2024-06-27 11:48   ` [PATCH v2 2/2] ui/cocoa: Adds NSCursor absolute pointer support Akihiko Odaki

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240625134931.92279-3-phil@philjordan.eu \
    --to=phil@philjordan.eu \
    --cc=akihiko.odaki@daynix.com \
    --cc=lists@philjordan.eu \
    --cc=marcandre.lureau@redhat.com \
    --cc=peter.maydell@linaro.org \
    --cc=philmd@linaro.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).