From nobody Mon Nov 25 01:55:51 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1719323428; cv=none; d=zohomail.com; s=zohoarc; b=Fmesn2eE6rDA3QxvRuRNeQgOZ9n0UjaBh2sbYksCA6c0WTyuw3EnzFrxd+Fuo7034k0SAcgNRJM/iRWkC+EQT26jvlhjf6N5DI6LHIXZl0uo1fJaMzecJshLt4LfROhAerIDLGGqQZFE3pPE9JT2WQU7E+xZn6gFW9sHiv0otRw= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1719323428; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=fblMUAK/+8LE6mBEBaO4iTmx3F9Zc50cn4A+rhgKV38=; b=BDi6Tzsmr7Td+MQGoF5VKcORg8xBg0D0FVLW8HBIvsfEsHzRPsThh+zOvvkmsGPfvh153EdZ8n0ebGpcbkepeF9ih2mJYwOxmRfbGxdiskOGHDFwznD0z1MbOHCOw7CuWjdPeWMVRBGokjsSyiF/4GZhz+OflJZmcKu/OKAHm4c= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1719323428188173.99015667958713; Tue, 25 Jun 2024 06:50:28 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sM6YZ-0006zN-N1; Tue, 25 Jun 2024 09:49:59 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sM6YX-0006yr-9d for qemu-devel@nongnu.org; Tue, 25 Jun 2024 09:49:57 -0400 Received: from mail-lj1-x229.google.com ([2a00:1450:4864:20::229]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1sM6YU-0007Kt-9X for qemu-devel@nongnu.org; Tue, 25 Jun 2024 09:49:56 -0400 Received: by mail-lj1-x229.google.com with SMTP id 38308e7fff4ca-2eaea28868dso73417441fa.3 for ; Tue, 25 Jun 2024 06:49:53 -0700 (PDT) Received: from localhost.localdomain (89-104-8-17.customer.bnet.at. [89.104.8.17]) by smtp.gmail.com with ESMTPSA id a640c23a62f3a-a726e13a4d7sm77299166b.19.2024.06.25.06.49.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 25 Jun 2024 06:49:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=philjordan-eu.20230601.gappssmtp.com; s=20230601; t=1719323392; x=1719928192; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=fblMUAK/+8LE6mBEBaO4iTmx3F9Zc50cn4A+rhgKV38=; b=qjTJdSNYDWKR/B+FuCQOeeQWKo8J83R4A3MmSyPLdDDdTc3fqfKWdJieEBkULSvdl4 Pl8d0IlU6x+f9psY3Amc13nBb8xvh2YFe8WJw4g4QZT+NV4XMc9uemmPfyDQb5PIjGuD ofDaks/5Db8UYGbP2sIIuAypeTUBHPOPp7IV6rTkX6RR7IfuZ9io+jfNW+V/T4cb/81O OY6FDFNCbmeYT7ylbsG5/TYqPTqcYT6w0jE/rIFCDC99Zg6ZpvsysxlR/1kIjkZ4XSu2 sjt1s9eN3g49EMoTY3c6ERQMZl7qxhliisi7JJYW+7YRxJK+MzDORP1JvKFQZgrPy5xy zRZg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1719323392; x=1719928192; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=fblMUAK/+8LE6mBEBaO4iTmx3F9Zc50cn4A+rhgKV38=; b=gipXhGSBIKEJV2OTdgKor71ApNipvr/r7itdSLDQRul8jMbzOzvg/Od7Iu7HO48LbK dpud3QpwmQcIoKDWyLA6iKvibYoRrwYNp4pomOkYncEQVntFKmLsvpjNF2wH7hqv40wi W8yQnO6Rhz/R4URpRZ/5/Y4Jm1Jew2fK1fIoxntTyl70ESNgpF4ujctbA26U0fQuqJYq DcyBu3IAVM+Sq4kpCbn3SuQDXl3A/RolH8LX2GkHc0R7Yiptb6IVz1O33CiAMBnKy3v9 BWAjIfhVr/VRiYh2K9/E1tUawFor09weM+rOA5+VU2hYvNrer+/uRAGzJ4beXm2pzPw8 z1aA== X-Gm-Message-State: AOJu0Yy41ZZzPr+sg0WCmOBUccm61vimWZlwzyHarxAoJwkKdOSSqNj4 ed59CYoBPyqyRXZNuTabdBv6YCGwdZy5j+avHb2ZjrT4ISNFmvNhULKMoslvagPCeCivAzDieDf gXA== X-Google-Smtp-Source: AGHT+IHrzcuQUcF8hirbaCMrHB+nev4Ps+eKDNJVnmxIXcXjtQGLOwwgbk5nzOp1ZPflW5qRvAIedw== X-Received: by 2002:a05:6512:48c5:b0:52c:dba2:4f1 with SMTP id 2adb3069b0e04-52ce18524e1mr4890998e87.48.1719323392538; Tue, 25 Jun 2024 06:49:52 -0700 (PDT) From: Phil Dennis-Jordan 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 Subject: [PATCH v2 2/2] ui/cocoa: Adds NSCursor absolute pointer support Date: Tue, 25 Jun 2024 15:49:31 +0200 Message-Id: <20240625134931.92279-3-phil@philjordan.eu> X-Mailer: git-send-email 2.39.3 (Apple Git-146) In-Reply-To: <20240625134931.92279-1-phil@philjordan.eu> References: <20240625134931.92279-1-phil@philjordan.eu> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: neutral client-ip=2a00:1450:4864:20::229; envelope-from=phil@philjordan.eu; helo=mail-lj1-x229.google.com X-Spam_score_int: -10 X-Spam_score: -1.1 X-Spam_bar: - X-Spam_report: (-1.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_NEUTRAL=0.779 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZohoMail-DKIM: pass (identity @philjordan-eu.20230601.gappssmtp.com) X-ZM-MESSAGEID: 1719323429760100003 When pointer input is absolute, use the native macOS host=E2=80=99s Cocoa NSCursor to render the guest=E2=80=99s cursor. The rendered cursor is no lo= nger cropped to the guest viewport, and the correct cursor image is passed to anything tapping into the host system=E2=80=99s native cursor. (such as rem= ote 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 --- 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 =20 [cursorLayer release]; cursorLayer =3D nil; + [cocoaCursor release]; + cocoaCursor =3D nil; + [super dealloc]; } =20 @@ -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]; } =20 -- (void)setCursor:(QEMUCursor *)given_cursor +static CGImageRef cursor_cgimage_create(QEMUCursor *cursor) { CGDataProviderRef provider; CGImageRef image; - CGRect bounds =3D CGRectZero; - - cursor_unref(cursor); - cursor =3D given_cursor; - - if (!cursor) { - return; - } - - cursor_ref(cursor); - - bounds.size.width =3D cursor->width; - bounds.size.height =3D cursor->height; CGColorSpaceRef color_space =3D CGColorSpaceCreateWithName(kCGColorSpa= ceSRGB); =20 provider =3D CGDataProviderCreateWithData( @@ -506,6 +497,43 @@ - (void)setCursor:(QEMUCursor *)given_cursor =20 CGDataProviderRelease(provider); CGColorSpaceRelease(color_space); + return image; +} + +static NSCursor *cocoa_cursor_create(QEMUCursor *cursor, CGImageRef image) +{ + NSPoint hotspot =3D { cursor->hot_x, cursor->hot_y }; + NSSize size =3D NSMakeSize(cursor->width, cursor->height); + NSImage *cursor_image =3D [[NSImage alloc] initWithCGImage:image size:= size]; + NSCursor *cocoa_cursor =3D + [[NSCursor alloc] initWithImage:cursor_image hotSpot:hotspot]; + [cursor_image release]; + return cocoa_cursor; +} + +- (void)setCursor:(QEMUCursor *)given_cursor +{ + CGImageRef image; + NSImage *cursor_nsimage =3D nil; + CGRect bounds =3D CGRectZero; + + cursor_unref(cursor); + cursor =3D given_cursor; + + if (!cursor) { + return; + } + + cursor_ref(cursor); + + bounds.size.width =3D cursor->width; + bounds.size.height =3D cursor->height; + + image =3D cursor_cgimage_create(cursor); + [cocoaCursor release]; + cocoaCursor =3D 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); } =20 +- (void)=C2=A0resetCursorRects +{ + if (self->cocoaCursor =3D=3D nil) { + [super resetCursorRects]; + } else { + NSRect guest_area =3D {{ 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 - (Pr= ess " 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 =3D TRUE; // while isMouseGrabbed =3D TRUE, QemuCocoaAp= p sends all events to [cocoaView handleEvent:] } @@ -1194,7 +1237,11 @@ - (void) ungrabMouse [[self window] setTitle:[NSString stringWithFormat:@"QEMU %s", qem= u_name]]; else [[self window] setTitle:@"QEMU"]; - [self unhideCursor]; + + [cursorLayer setHidden:!mouseOn || isAbsoluteEnabled]; + if (!isAbsoluteEnabled) { + [self unhideCursor]; + } CGAssociateMouseAndMouseCursorPosition(TRUE); isMouseGrabbed =3D FALSE; [self raiseAllButtons]; @@ -1216,6 +1263,7 @@ - (void) notifyMouseModeChange { [self ungrabMouse]; } else { CGAssociateMouseAndMouseCursorPosition(isAbsoluteEnabled); + [self hideCursor]; } } } --=20 2.39.3 (Apple Git-146)