From patchwork Tue Jun 25 13:49:30 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Phil Dennis-Jordan X-Patchwork-Id: 1952118 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=philjordan-eu.20230601.gappssmtp.com header.i=@philjordan-eu.20230601.gappssmtp.com header.a=rsa-sha256 header.s=20230601 header.b=x1/IXBqc; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4W7mS86d3Pz214Y for ; Tue, 25 Jun 2024 23:50:32 +1000 (AEST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sM6YZ-0006zJ-FF; 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 1sM6YV-0006x0-Ok for qemu-devel@nongnu.org; Tue, 25 Jun 2024 09:49:55 -0400 Received: from mail-ej1-x636.google.com ([2a00:1450:4864:20::636]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1sM6YT-0007KH-Kc for qemu-devel@nongnu.org; Tue, 25 Jun 2024 09:49:54 -0400 Received: by mail-ej1-x636.google.com with SMTP id a640c23a62f3a-a6f8ebbd268so1085822866b.0 for ; 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=1719323391; x=1719928191; 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=RJhNG6W/u2QBb+Lr2mxjHC9Dx9KTVbi65U/cSPuIL0U=; b=x1/IXBqc0fKLBKQ0jl9Mr4me0mNZtKVp4veVJYLjZyA83eEjFIlM69nUwy6ifAOX1O rBGqvB7s1EDbsFdACIcs5EylrYEskK1nEWXt+1cViHhs/ndHsUzMkAyIqRYRVY/HQ2t9 /CvBYxXXu+hgqXJuUA5FwfOxjHkcX/KofIE4DUCCDZKOsy3/OvzDpv0NBGZNK/t7IiHB 7BjWmdgGy3Akc6X7yRNYCX0aolVpi4YnbF4I7A8ki3U6+3S5YU55a3NmNtpCFm5NXPHm 2gyw2Yf/VnaCM+j+hyO0llLhJGo1qz8qgEIIG+PCL4UIn/ZIJ4XnDWSVG9HZBh+yiRZN RyDg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1719323391; x=1719928191; 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=RJhNG6W/u2QBb+Lr2mxjHC9Dx9KTVbi65U/cSPuIL0U=; b=f5DIEzowKgwgwRUEgX6hWcnppXAhU0oBtwyTSGYv1+LaZEsCh5Y1ppHbEbbbOkmzQ+ rh2cjwYlnwR/CEUpAfeMtvWelFyzJCwLFbJfWdYbw4fKaBOzByS+8FyzOfLSQPZhHGoQ O68wsbFUgIw6/z2RdjleAXKzK2aZM3VmljCKXzeqapdYsb4x50dpooNIqJWsmRoTO3nd 7+QLSMe0C7UWf5XPkrvfrEhMFcEM+Qw4hlG1bykQ+oxUqLSd8lZKnMJb10PPDjnP1N9J yH7NUE0AndpDUkjP/EkuSabIebfmHp31+UDaNAfd5c2e26kW286KPlM1zQV8vmvh9NN0 6fkA== X-Gm-Message-State: AOJu0YypOfysUTMM59xKiKlV2nOJvMBkLImlgdsiLUHLEiGYNsW9Q4/c 6dtpfds6uMpp7W7/YXiCtekFnYI0J+0GWJHn/KQmULqvWpiK3J8siWYptZxwWZyE9BaRjTYE85P xwQ== X-Google-Smtp-Source: AGHT+IHkWoyye5aFgxtGCab24XrPAMz+pZCcRPfDgntmT+aNwSZpZQdQrI8K/fY4jjOp778PEcE+vQ== X-Received: by 2002:a17:906:57cb:b0:a6f:e3e4:e0b6 with SMTP id a640c23a62f3a-a700e70884emr725231766b.27.1719323390852; Tue, 25 Jun 2024 06:49:50 -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.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 25 Jun 2024 06:49:50 -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 1/2] ui/cocoa: Minor fixes to CALayer based cursors Date: Tue, 25 Jun 2024 15:49:30 +0200 Message-Id: <20240625134931.92279-2-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 Received-SPF: neutral client-ip=2a00:1450:4864:20::636; envelope-from=phil@philjordan.eu; helo=mail-ej1-x636.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+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org This change fixes some object lifetime issues. (Unreleased reference counts) Signed-off-by: Phil Dennis-Jordan --- ui/cocoa.m | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/ui/cocoa.m b/ui/cocoa.m index 06ca114800..cca987eac7 100644 --- a/ui/cocoa.m +++ b/ui/cocoa.m @@ -395,6 +395,13 @@ - (void) dealloc CFRelease(eventsTap); } + if (cursor) { + cursor_unref(cursor); + cursor = NULL; + } + + [cursorLayer release]; + cursorLayer = nil; [super dealloc]; } @@ -474,6 +481,7 @@ - (void)setCursor:(QEMUCursor *)given_cursor bounds.size.width = cursor->width; bounds.size.height = cursor->height; + CGColorSpaceRef color_space = CGColorSpaceCreateWithName(kCGColorSpaceSRGB); provider = CGDataProviderCreateWithData( NULL, @@ -488,7 +496,7 @@ - (void)setCursor:(QEMUCursor *)given_cursor 8, //bitsPerComponent 32, //bitsPerPixel cursor->width * 4, //bytesPerRow - CGColorSpaceCreateWithName(kCGColorSpaceSRGB), //colorspace + color_space, //colorspace kCGBitmapByteOrder32Little | kCGImageAlphaFirst, //bitmapInfo provider, //provider NULL, //decode @@ -497,6 +505,7 @@ - (void)setCursor:(QEMUCursor *)given_cursor ); CGDataProviderRelease(provider); + CGColorSpaceRelease(color_space); [CATransaction begin]; [CATransaction setDisableActions:YES]; [cursorLayer setBounds:bounds]; From patchwork Tue Jun 25 13:49:31 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Phil Dennis-Jordan X-Patchwork-Id: 1952116 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=philjordan-eu.20230601.gappssmtp.com header.i=@philjordan-eu.20230601.gappssmtp.com header.a=rsa-sha256 header.s=20230601 header.b=qjTJdSNY; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4W7mS86Xszz20X1 for ; Tue, 25 Jun 2024 23:50:29 +1000 (AEST) 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) 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) 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) 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 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+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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 --- 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]; } } }