|
@@ -25,6 +25,7 @@
|
|
|
#include "qemu/osdep.h"
|
|
|
|
|
|
#import <Cocoa/Cocoa.h>
|
|
|
+#import <QuartzCore/QuartzCore.h>
|
|
|
#include <crt_externs.h>
|
|
|
|
|
|
#include "qemu/help-texts.h"
|
|
@@ -79,12 +80,16 @@ static void cocoa_switch(DisplayChangeListener *dcl,
|
|
|
DisplaySurface *surface);
|
|
|
|
|
|
static void cocoa_refresh(DisplayChangeListener *dcl);
|
|
|
+static void cocoa_mouse_set(DisplayChangeListener *dcl, int x, int y, bool on);
|
|
|
+static void cocoa_cursor_define(DisplayChangeListener *dcl, QEMUCursor *cursor);
|
|
|
|
|
|
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,
|
|
@@ -308,6 +313,11 @@ @interface QemuCocoaView : NSView
|
|
|
BOOL isAbsoluteEnabled;
|
|
|
CFMachPortRef eventsTap;
|
|
|
CGColorSpaceRef colorspace;
|
|
|
+ CALayer *cursorLayer;
|
|
|
+ QEMUCursor *cursor;
|
|
|
+ int mouseX;
|
|
|
+ int mouseY;
|
|
|
+ bool mouseOn;
|
|
|
}
|
|
|
- (void) switchSurface:(pixman_image_t *)image;
|
|
|
- (void) grabMouse;
|
|
@@ -364,6 +374,12 @@ - (id)initWithFrame:(NSRect)frameRect
|
|
|
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_14_0
|
|
|
[self setClipsToBounds:YES];
|
|
|
#endif
|
|
|
+ [self setWantsLayer:YES];
|
|
|
+ cursorLayer = [[CALayer alloc] init];
|
|
|
+ [cursorLayer setAnchorPoint:CGPointMake(0, 1)];
|
|
|
+ [cursorLayer setAutoresizingMask:kCALayerMaxXMargin |
|
|
|
+ kCALayerMinYMargin];
|
|
|
+ [[self layer] addSublayer:cursorLayer];
|
|
|
|
|
|
}
|
|
|
return self;
|
|
@@ -382,6 +398,8 @@ - (void) dealloc
|
|
|
}
|
|
|
|
|
|
CGColorSpaceRelease(colorspace);
|
|
|
+ [cursorLayer release];
|
|
|
+ cursor_unref(cursor);
|
|
|
[super dealloc];
|
|
|
}
|
|
|
|
|
@@ -426,6 +444,72 @@ - (void) unhideCursor
|
|
|
[NSCursor unhide];
|
|
|
}
|
|
|
|
|
|
+- (void)setMouseX:(int)x y:(int)y on:(bool)on
|
|
|
+{
|
|
|
+ CGPoint position;
|
|
|
+
|
|
|
+ mouseX = x;
|
|
|
+ mouseY = y;
|
|
|
+ mouseOn = on;
|
|
|
+
|
|
|
+ position.x = mouseX;
|
|
|
+ position.y = screen.height - mouseY;
|
|
|
+
|
|
|
+ [CATransaction begin];
|
|
|
+ [CATransaction setDisableActions:YES];
|
|
|
+ [cursorLayer setPosition:position];
|
|
|
+ [cursorLayer setHidden:!mouseOn];
|
|
|
+ [CATransaction commit];
|
|
|
+}
|
|
|
+
|
|
|
+- (void)setCursor:(QEMUCursor *)given_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;
|
|
|
+
|
|
|
+ provider = CGDataProviderCreateWithData(
|
|
|
+ NULL,
|
|
|
+ cursor->data,
|
|
|
+ cursor->width * cursor->height * 4,
|
|
|
+ NULL
|
|
|
+ );
|
|
|
+
|
|
|
+ image = CGImageCreate(
|
|
|
+ cursor->width, //width
|
|
|
+ cursor->height, //height
|
|
|
+ 8, //bitsPerComponent
|
|
|
+ 32, //bitsPerPixel
|
|
|
+ cursor->width * 4, //bytesPerRow
|
|
|
+ colorspace, //colorspace
|
|
|
+ kCGBitmapByteOrder32Little | kCGImageAlphaFirst, //bitmapInfo
|
|
|
+ provider, //provider
|
|
|
+ NULL, //decode
|
|
|
+ 0, //interpolate
|
|
|
+ kCGRenderingIntentDefault //intent
|
|
|
+ );
|
|
|
+
|
|
|
+ CGDataProviderRelease(provider);
|
|
|
+ [CATransaction begin];
|
|
|
+ [CATransaction setDisableActions:YES];
|
|
|
+ [cursorLayer setBounds:bounds];
|
|
|
+ [cursorLayer setContents:(id)image];
|
|
|
+ [CATransaction commit];
|
|
|
+ CGImageRelease(image);
|
|
|
+}
|
|
|
+
|
|
|
- (void) drawRect:(NSRect) rect
|
|
|
{
|
|
|
COCOA_DEBUG("QemuCocoaView: drawRect\n");
|
|
@@ -2015,6 +2099,21 @@ static void cocoa_refresh(DisplayChangeListener *dcl)
|
|
|
[pool release];
|
|
|
}
|
|
|
|
|
|
+static void cocoa_mouse_set(DisplayChangeListener *dcl, int x, int y, bool on)
|
|
|
+{
|
|
|
+ dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
+ [cocoaView setMouseX:x y:y on:on];
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+static void cocoa_cursor_define(DisplayChangeListener *dcl, QEMUCursor *cursor)
|
|
|
+{
|
|
|
+ dispatch_async(dispatch_get_main_queue(), ^{
|
|
|
+ BQL_LOCK_GUARD();
|
|
|
+ [cocoaView setCursor:qemu_console_get_cursor(dcl->con)];
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
static void cocoa_display_init(DisplayState *ds, DisplayOptions *opts)
|
|
|
{
|
|
|
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
|