mirror of
https://github.com/xemu-project/xemu.git
synced 2024-11-23 11:39:53 +00:00
ui/cocoa: Add clipboard support
Signed-off-by: Akihiko Odaki <akihiko.odaki@gmail.com> Message-Id: <20210616141954.54291-1-akihiko.odaki@gmail.com> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
This commit is contained in:
parent
15280e85d7
commit
7e3e20d891
@ -187,7 +187,7 @@ void qemu_clipboard_set_data(QemuClipboardPeer *peer,
|
||||
QemuClipboardInfo *info,
|
||||
QemuClipboardType type,
|
||||
uint32_t size,
|
||||
void *data,
|
||||
const void *data,
|
||||
bool update);
|
||||
|
||||
#endif /* QEMU_CLIPBOARD_H */
|
||||
|
@ -73,7 +73,7 @@ void qemu_clipboard_set_data(QemuClipboardPeer *peer,
|
||||
QemuClipboardInfo *info,
|
||||
QemuClipboardType type,
|
||||
uint32_t size,
|
||||
void *data,
|
||||
const void *data,
|
||||
bool update)
|
||||
{
|
||||
if (!info ||
|
||||
|
109
ui/cocoa.m
109
ui/cocoa.m
@ -28,6 +28,7 @@
|
||||
#include <crt_externs.h>
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "ui/clipboard.h"
|
||||
#include "ui/console.h"
|
||||
#include "ui/input.h"
|
||||
#include "ui/kbd-state.h"
|
||||
@ -105,6 +106,10 @@ static QemuSemaphore display_init_sem;
|
||||
static QemuSemaphore app_started_sem;
|
||||
static bool allow_events;
|
||||
|
||||
static NSInteger cbchangecount = -1;
|
||||
static QemuClipboardInfo *cbinfo;
|
||||
static QemuEvent cbevent;
|
||||
|
||||
// Utility functions to run specified code block with iothread lock held
|
||||
typedef void (^CodeBlock)(void);
|
||||
typedef bool (^BoolCodeBlock)(void);
|
||||
@ -1758,6 +1763,93 @@ static void addRemovableDevicesMenuItems(void)
|
||||
qapi_free_BlockInfoList(pointerToFree);
|
||||
}
|
||||
|
||||
@interface QemuCocoaPasteboardTypeOwner : NSObject<NSPasteboardTypeOwner>
|
||||
@end
|
||||
|
||||
@implementation QemuCocoaPasteboardTypeOwner
|
||||
|
||||
- (void)pasteboard:(NSPasteboard *)sender provideDataForType:(NSPasteboardType)type
|
||||
{
|
||||
if (type != NSPasteboardTypeString) {
|
||||
return;
|
||||
}
|
||||
|
||||
with_iothread_lock(^{
|
||||
QemuClipboardInfo *info = qemu_clipboard_info_ref(cbinfo);
|
||||
qemu_event_reset(&cbevent);
|
||||
qemu_clipboard_request(info, QEMU_CLIPBOARD_TYPE_TEXT);
|
||||
|
||||
while (info == cbinfo &&
|
||||
info->types[QEMU_CLIPBOARD_TYPE_TEXT].available &&
|
||||
info->types[QEMU_CLIPBOARD_TYPE_TEXT].data == NULL) {
|
||||
qemu_mutex_unlock_iothread();
|
||||
qemu_event_wait(&cbevent);
|
||||
qemu_mutex_lock_iothread();
|
||||
}
|
||||
|
||||
if (info == cbinfo) {
|
||||
NSData *data = [[NSData alloc] initWithBytes:info->types[QEMU_CLIPBOARD_TYPE_TEXT].data
|
||||
length:info->types[QEMU_CLIPBOARD_TYPE_TEXT].size];
|
||||
[sender setData:data forType:NSPasteboardTypeString];
|
||||
[data release];
|
||||
}
|
||||
|
||||
qemu_clipboard_info_unref(info);
|
||||
});
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
static QemuCocoaPasteboardTypeOwner *cbowner;
|
||||
|
||||
static void cocoa_clipboard_notify(Notifier *notifier, void *data);
|
||||
static void cocoa_clipboard_request(QemuClipboardInfo *info,
|
||||
QemuClipboardType type);
|
||||
|
||||
static QemuClipboardPeer cbpeer = {
|
||||
.name = "cocoa",
|
||||
.update = { .notify = cocoa_clipboard_notify },
|
||||
.request = cocoa_clipboard_request
|
||||
};
|
||||
|
||||
static void cocoa_clipboard_notify(Notifier *notifier, void *data)
|
||||
{
|
||||
QemuClipboardInfo *info = data;
|
||||
|
||||
if (info->owner == &cbpeer || info->selection != QEMU_CLIPBOARD_SELECTION_CLIPBOARD) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (info != cbinfo) {
|
||||
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
|
||||
qemu_clipboard_info_unref(cbinfo);
|
||||
cbinfo = qemu_clipboard_info_ref(info);
|
||||
cbchangecount = [[NSPasteboard generalPasteboard] declareTypes:@[NSPasteboardTypeString] owner:cbowner];
|
||||
[pool release];
|
||||
}
|
||||
|
||||
qemu_event_set(&cbevent);
|
||||
}
|
||||
|
||||
static void cocoa_clipboard_request(QemuClipboardInfo *info,
|
||||
QemuClipboardType type)
|
||||
{
|
||||
NSData *text;
|
||||
|
||||
switch (type) {
|
||||
case QEMU_CLIPBOARD_TYPE_TEXT:
|
||||
text = [[NSPasteboard generalPasteboard] dataForType:NSPasteboardTypeString];
|
||||
if (text) {
|
||||
qemu_clipboard_set_data(&cbpeer, info, type,
|
||||
[text length], [text bytes], true);
|
||||
[text release];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The startup process for the OSX/Cocoa UI is complicated, because
|
||||
* OSX insists that the UI runs on the initial main thread, and so we
|
||||
@ -1792,6 +1884,7 @@ static void *call_qemu_main(void *opaque)
|
||||
COCOA_DEBUG("Second thread: calling qemu_main()\n");
|
||||
status = qemu_main(gArgc, gArgv, *_NSGetEnviron());
|
||||
COCOA_DEBUG("Second thread: qemu_main() returned, exiting\n");
|
||||
[cbowner release];
|
||||
exit(status);
|
||||
}
|
||||
|
||||
@ -1914,6 +2007,18 @@ static void cocoa_refresh(DisplayChangeListener *dcl)
|
||||
[cocoaView setAbsoluteEnabled:YES];
|
||||
});
|
||||
}
|
||||
|
||||
if (cbchangecount != [[NSPasteboard generalPasteboard] changeCount]) {
|
||||
qemu_clipboard_info_unref(cbinfo);
|
||||
cbinfo = qemu_clipboard_info_new(&cbpeer, QEMU_CLIPBOARD_SELECTION_CLIPBOARD);
|
||||
if ([[NSPasteboard generalPasteboard] availableTypeFromArray:@[NSPasteboardTypeString]]) {
|
||||
cbinfo->types[QEMU_CLIPBOARD_TYPE_TEXT].available = true;
|
||||
}
|
||||
qemu_clipboard_update(cbinfo);
|
||||
cbchangecount = [[NSPasteboard generalPasteboard] changeCount];
|
||||
qemu_event_set(&cbevent);
|
||||
}
|
||||
|
||||
[pool release];
|
||||
}
|
||||
|
||||
@ -1939,6 +2044,10 @@ static void cocoa_display_init(DisplayState *ds, DisplayOptions *opts)
|
||||
|
||||
// register vga output callbacks
|
||||
register_displaychangelistener(&dcl);
|
||||
|
||||
qemu_event_init(&cbevent, false);
|
||||
cbowner = [[QemuCocoaPasteboardTypeOwner alloc] init];
|
||||
qemu_clipboard_peer_register(&cbpeer);
|
||||
}
|
||||
|
||||
static QemuDisplay qemu_display_cocoa = {
|
||||
|
Loading…
Reference in New Issue
Block a user