From: Zhang Chen <tgfbeta@me.com>
To: qemu-devel@nongnu.org
Cc: Zhang Chen <tgfbeta@me.com>,
Peter Maydell <peter.maydell@linaro.org>,
Gerd Hoffmann <kraxel@redhat.com>
Subject: [PATCH] ui/cocoa: Implement dcl operators for guest cursor
Date: Tue, 10 Aug 2021 17:17:06 +0800 [thread overview]
Message-ID: <20210810091706.65576-1-tgfbeta@me.com> (raw)
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.
Signed-off-by: Zhang Chen <tgfbeta@me.com>
---
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;
static void cocoa_update(DisplayChangeListener *dcl,
@@ -83,12 +85,19 @@ static void cocoa_switch(DisplayChangeListener *dcl,
static void cocoa_refresh(DisplayChangeListener *dcl);
+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 = {
.dpy_name = "cocoa",
.dpy_gfx_update = cocoa_update,
.dpy_gfx_switch = cocoa_switch,
.dpy_refresh = cocoa_refresh,
+ .dpy_mouse_set = cocoa_mouse_set,
+ .dpy_cursor_define = cocoa_cursor_define,
};
static DisplayChangeListener dcl = {
.ops = &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 = [super initWithFrame:frameRect];
if (self) {
+ screen.bitsPerComponent = 8;
+ screen.bitsPerPixel = 32;
screen.width = frameRect.size.width;
screen.height = frameRect.size.height;
kbd = qkbd_state_init(dcl.con);
@@ -484,6 +498,12 @@ QemuCocoaView *cocoaView;
);
CGContextDrawImage (viewContextRef, cgrect(rectList[i]), clipImageRef);
CGImageRelease (clipImageRef);
+
+ }
+ CGRect cursorDrawRect = stretch_video ?
+ [self convertRectFromQemuScreen:cursorRect] : cursorRect;
+ if (cursorVisible && cursorImage && NSIntersectsRect(rect, cursorDrawRect)) {
+ CGContextDrawImage (viewContextRef, cursorDrawRect, cursorImage);
}
CGImageRelease (imageRef);
CGDataProviderRelease(dataProviderRef);
@@ -1075,6 +1095,28 @@ QemuCocoaView *cocoaView;
- (float) cdy {return cdy;}
- (QEMUScreen) gscreen {return screen;}
+- (CGRect) cursorRect {return cursorRect;}
+- (void) setCursorRect:(CGRect)rect {cursorRect = rect;}
+- (CGImageRef) cursorImage {return cursorImage;}
+- (void) setCursorImage:(CGImageRef)image
+{
+ if (cursorImage && cursorImage != image) {
+ CGImageRelease(cursorImage);
+ }
+ cursorImage = image;
+}
+- (BOOL) isCursorVisible {return cursorVisible;}
+- (void) setCursorVisible:(BOOL)visible {cursorVisible = visible;}
+
+- (CGRect) convertRectFromQemuScreen:(CGRect)rect
+{
+ CGRect viewRect = rect;
+ viewRect.origin.x *= cdx;
+ viewRect.origin.y *= cdy;
+ viewRect.size.width *= cdx;
+ viewRect.size.height *= 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];
}
+static void cocoa_cursor_define(DisplayChangeListener *dcl, QEMUCursor *c)
+{
+ NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+ int bitsPerComponent = [cocoaView gscreen].bitsPerComponent;
+ int bitsPerPixel = [cocoaView gscreen].bitsPerPixel;
+ int stride = c->width * bitsPerComponent / 2;
+ CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, c->data, c->width * 4 * c->height, NULL);
+
+ CGImageRef img = CGImageCreate(
+ c->width,
+ c->height,
+ bitsPerComponent,
+ bitsPerPixel,
+ stride,
+ CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB), //colorspace
+ kCGBitmapByteOrder32Little | kCGImageAlphaFirst,
+ provider,
+ NULL,
+ 0,
+ kCGRenderingIntentDefault
+ );
+
+ CGDataProviderRelease(provider);
+ CGFloat width = c->width;
+ CGFloat height = c->height;
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [cocoaView setCursorImage:img];
+ CGRect rect = [cocoaView cursorRect];
+ rect.size = CGSizeMake(width, height);
+ [cocoaView setCursorRect:rect];
+ });
+ [pool release];
+}
+
+static void cocoa_mouse_set(DisplayChangeListener *dcl,
+ int x, int y, int visible)
+{
+ NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+ dispatch_async(dispatch_get_main_queue(), ^{
+ QEMUScreen screen = [cocoaView gscreen];
+ // Mark old cursor rect as dirty
+ CGRect rect = [cocoaView cursorRect];
+ CGRect dirtyRect = stretch_video ?
+ [cocoaView convertRectFromQemuScreen:rect] : rect;
+ [cocoaView setNeedsDisplayInRect:dirtyRect];
+ // Update rect for cursor sprite
+ rect.origin = CGPointMake(x, screen.height - (y + rect.size.height));
+ [cocoaView setCursorRect:rect];
+ [cocoaView setCursorVisible:visible ? YES : NO];
+ // Mark new cursor rect as dirty
+ dirtyRect = 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");
--
2.30.2
next reply other threads:[~2021-08-10 9:18 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-08-10 9:17 Zhang Chen [this message]
-- strict thread matches above, loose matches on Subject: below --
2021-08-10 8:37 [PATCH] ui/cocoa: Implement dcl operators for guest cursor Zhang Chen via
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=20210810091706.65576-1-tgfbeta@me.com \
--to=tgfbeta@me.com \
--cc=kraxel@redhat.com \
--cc=peter.maydell@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).