From nobody Sun May 19 06:23:07 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; 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; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1628585611; cv=none; d=zohomail.com; s=zohoarc; b=csDZ0ucWtB3OiMFbHHSkws08d3+4dkMtT7Uo+8uQezTcrDbHdbAJFUPg+4h5F5VT192myYjLhu60tdLZ6BQOfRXmgxsCRrSjz95L3g5q8T+u7EjPZbbTN6hnb5HfEgU37U8fXp5z2rd7BPEpwInsrEKAZvt7LDTpmrd/C6DBO0w= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1628585611; h=Content-Transfer-Encoding:Cc:Date:From:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Sender:Subject:To; bh=1XcAew3dZi4jnmP0h8+pLGlvQoUE8GVdAH19tV3T30o=; b=MUiNxBnOaXCuyZusOJTOvFZLkpWEkLnIq7a5l3l60XOwox4detkzPC5SuV04qGErW0cE31M2B+NM7c8AJeaGi5kv9xwvCcKKwYGbiNOLodcel1KrM9ZKz5GHPW7PH1+I+4XDdR4o/nK3mm3O/H+W6lEp6onItdxtGwgd/vYsSWQ= ARC-Authentication-Results: i=1; mx.zohomail.com; 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; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1628585611272323.76862390258304; Tue, 10 Aug 2021 01:53:31 -0700 (PDT) Received: from localhost ([::1]:60316 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1mDNVp-0005kM-L4 for importer@patchew.org; Tue, 10 Aug 2021 04:53:29 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:38728) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mDNR0-0003RV-9u for qemu-devel@nongnu.org; Tue, 10 Aug 2021 04:48:30 -0400 Received: from [125.38.22.94] (port=52035 helo=bogon.localdomain) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1mDNQw-0000z2-DQ for qemu-devel@nongnu.org; Tue, 10 Aug 2021 04:48:30 -0400 Received: by bogon.localdomain (Postfix, from userid 501) id 3991619ED166; Tue, 10 Aug 2021 16:37:33 +0800 (CST) To: qemu-devel@nongnu.org Cc: Zhang Chen , Peter Maydell , Gerd Hoffmann Subject: [PATCH] ui/cocoa: Implement dcl operators for guest cursor Date: Tue, 10 Aug 2021 16:37:05 +0800 Message-Id: <20210810083706.64777-1-tgfbeta@me.com> X-Mailer: git-send-email 2.30.2 MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Host-Lookup-Failed: Reverse DNS lookup failed for 125.38.22.94 (failed) 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: none client-ip=125.38.22.94; envelope-from=cuser@bogon.localdomain; helo=bogon.localdomain X-Spam_score_int: 35 X-Spam_score: 3.5 X-Spam_bar: +++ X-Spam_report: (3.5 / 5.0 requ) BAYES_00=-1.9, FREEMAIL_FORGED_FROMDOMAIN=0.249, FREEMAIL_FROM=0.001, HEADER_FROM_DIFFERENT_DOMAINS=0.248, NO_DNS_FOR_FROM=0.001, RCVD_IN_PBL=3.335, RDNS_NONE=0.793, SPF_HELO_NONE=0.001, SPF_NONE=0.001, SPOOFED_FREEMAIL=0.726, SPOOFED_FREEMAIL_NO_RDNS=0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 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" Reply-to: Zhang Chen From: Zhang Chen via X-ZM-MESSAGEID: 1628585613671100001 Content-Type: text/plain; charset="utf-8" In this patch, two dcl operators were implemented for Cocoa display, to prepare, update and draw guest cursor on screen canvas. After this implementation, Cocoa display could support virtio-vga device, which is better supported in guest side, especially for Linux. In contrast to the default vga device, virtio-vga with dcl operators for cursors showed less flicker in cursor drawing. Two fields were added in the struct QemuScreen to pass dimensions to dcl operators. --- ui/cocoa.m | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/ui/cocoa.m b/ui/cocoa.m index 68a6302184..9d3a8eac28 100644 --- a/ui/cocoa.m +++ b/ui/cocoa.m @@ -73,6 +73,8 @@ typedef struct { int width; int height; + int bitsPerComponent; + int bitsPerPixel; } QEMUScreen; =20 static void cocoa_update(DisplayChangeListener *dcl, @@ -83,12 +85,19 @@ static void cocoa_switch(DisplayChangeListener *dcl, =20 static void cocoa_refresh(DisplayChangeListener *dcl); =20 +static void cocoa_mouse_set(DisplayChangeListener *dcl, + int x, int y, int visible); + +static void cocoa_cursor_define(DisplayChangeListener *dcl, QEMUCursor *c); + static NSWindow *normalWindow, *about_window; static const DisplayChangeListenerOps dcl_ops =3D { .dpy_name =3D "cocoa", .dpy_gfx_update =3D cocoa_update, .dpy_gfx_switch =3D cocoa_switch, .dpy_refresh =3D cocoa_refresh, + .dpy_mouse_set =3D cocoa_mouse_set, + .dpy_cursor_define =3D cocoa_cursor_define, }; static DisplayChangeListener dcl =3D { .ops =3D &dcl_ops, @@ -309,6 +318,9 @@ static void handleAnyDeviceErrors(Error * err) BOOL isMouseGrabbed; BOOL isFullscreen; BOOL isAbsoluteEnabled; + CGRect cursorRect; + CGImageRef cursorImage; + BOOL cursorVisible; } - (void) switchSurface:(pixman_image_t *)image; - (void) grabMouse; @@ -344,6 +356,8 @@ QemuCocoaView *cocoaView; self =3D [super initWithFrame:frameRect]; if (self) { =20 + screen.bitsPerComponent =3D 8; + screen.bitsPerPixel =3D 32; screen.width =3D frameRect.size.width; screen.height =3D frameRect.size.height; kbd =3D qkbd_state_init(dcl.con); @@ -484,6 +498,12 @@ QemuCocoaView *cocoaView; ); CGContextDrawImage (viewContextRef, cgrect(rectList[i]), clipI= mageRef); CGImageRelease (clipImageRef); + + } + CGRect cursorDrawRect =3D stretch_video ? + [self convertRectFromQemuScreen:cursor= Rect] : cursorRect; + if (cursorVisible && cursorImage && NSIntersectsRect(rect, cursorD= rawRect)) { + CGContextDrawImage (viewContextRef, cursorDrawRect, cursorImag= e); } CGImageRelease (imageRef); CGDataProviderRelease(dataProviderRef); @@ -1075,6 +1095,28 @@ QemuCocoaView *cocoaView; - (float) cdy {return cdy;} - (QEMUScreen) gscreen {return screen;} =20 +- (CGRect) cursorRect {return cursorRect;} +- (void) setCursorRect:(CGRect)rect {cursorRect =3D rect;} +- (CGImageRef) cursorImage {return cursorImage;} +- (void) setCursorImage:(CGImageRef)image +{ + if (cursorImage && cursorImage !=3D image) { + CGImageRelease(cursorImage); + } + cursorImage =3D image; +} +- (BOOL) isCursorVisible {return cursorVisible;} +- (void) setCursorVisible:(BOOL)visible {cursorVisible =3D visible;} + +- (CGRect) convertRectFromQemuScreen:(CGRect)rect +{ + CGRect viewRect =3D rect; + viewRect.origin.x *=3D cdx; + viewRect.origin.y *=3D cdy; + viewRect.size.width *=3D cdx; + viewRect.size.height *=3D cdy; + return viewRect; +} /* * Makes the target think all down keys are being released. * This prevents a stuck key problem, since we will not see @@ -2022,6 +2064,63 @@ static void cocoa_refresh(DisplayChangeListener *dcl) [pool release]; } =20 +static void cocoa_cursor_define(DisplayChangeListener *dcl, QEMUCursor *c) +{ + NSAutoreleasePool * pool =3D [[NSAutoreleasePool alloc] init]; + int bitsPerComponent =3D [cocoaView gscreen].bitsPerComponent; + int bitsPerPixel =3D [cocoaView gscreen].bitsPerPixel; + int stride =3D c->width * bitsPerComponent / 2; + CGDataProviderRef provider =3D CGDataProviderCreateWithData(NULL, c->d= ata, c->width * 4 * c->height, NULL); + + CGImageRef img =3D CGImageCreate( + c->width, + c->height, + bitsPerComponent, + bitsPerPixel, + stride, + CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB), //colorspace + kCGBitmapByteOrder32Little | kCGImageAlphaFirst, + provider, + NULL, + 0, + kCGRenderingIntentDefault + ); + + CGDataProviderRelease(provider); + CGFloat width =3D c->width; + CGFloat height =3D c->height; + dispatch_async(dispatch_get_main_queue(), ^{ + [cocoaView setCursorImage:img]; + CGRect rect =3D [cocoaView cursorRect]; + rect.size =3D CGSizeMake(width, height); + [cocoaView setCursorRect:rect]; + }); + [pool release]; +} + +static void cocoa_mouse_set(DisplayChangeListener *dcl, + int x, int y, int visible) +{ + NSAutoreleasePool * pool =3D [[NSAutoreleasePool alloc] init]; + dispatch_async(dispatch_get_main_queue(), ^{ + QEMUScreen screen =3D [cocoaView gscreen]; + // Mark old cursor rect as dirty + CGRect rect =3D [cocoaView cursorRect]; + CGRect dirtyRect =3D stretch_video ? + [cocoaView convertRectFromQemuScreen:rect] : rect; + [cocoaView setNeedsDisplayInRect:dirtyRect]; + // Update rect for cursor sprite + rect.origin =3D CGPointMake(x, screen.height - (y + rect.size.heig= ht)); + [cocoaView setCursorRect:rect]; + [cocoaView setCursorVisible:visible ? YES : NO]; + // Mark new cursor rect as dirty + dirtyRect =3D stretch_video ? + [cocoaView convertRectFromQemuScreen:rect] : rect; + [cocoaView setNeedsDisplayInRect:dirtyRect]; + }); + [pool release]; +} + static void cocoa_display_init(DisplayState *ds, DisplayOptions *opts) { COCOA_DEBUG("qemu_cocoa: cocoa_display_init\n"); --=20 2.30.2