28
28
#include <crt_externs.h>
29
29
30
30
#include "qemu-common.h"
31
+
#include "ui/clipboard.h"
31
32
#include "ui/console.h"
32
33
#include "ui/input.h"
33
34
#include "ui/kbd-state.h"
@@ -105,6 +106,10 @@ static void cocoa_switch(DisplayChangeListener *dcl,
105
106
static QemuSemaphore app_started_sem;
106
107
static bool allow_events;
107
108
109
+
static NSInteger cbchangecount = -1;
110
+
static QemuClipboardInfo *cbinfo;
111
+
static QemuEvent cbevent;
112
+
108
113
// Utility functions to run specified code block with iothread lock held
109
114
typedef void (^CodeBlock)(void);
110
115
typedef bool (^BoolCodeBlock)(void);
@@ -1758,6 +1763,93 @@ static void addRemovableDevicesMenuItems(void)
1758
1763
qapi_free_BlockInfoList(pointerToFree);
1759
1764
}
1760
1765
1766
+
@interface QemuCocoaPasteboardTypeOwner : NSObject<NSPasteboardTypeOwner>
1767
+
@end
1768
+
1769
+
@implementation QemuCocoaPasteboardTypeOwner
1770
+
1771
+
- (void)pasteboard:(NSPasteboard *)sender provideDataForType:(NSPasteboardType)type
1772
+
{
1773
+
if (type != NSPasteboardTypeString) {
1774
+
return;
1775
+
}
1776
+
1777
+
with_iothread_lock(^{
1778
+
QemuClipboardInfo *info = qemu_clipboard_info_ref(cbinfo);
1779
+
qemu_event_reset(&cbevent);
1780
+
qemu_clipboard_request(info, QEMU_CLIPBOARD_TYPE_TEXT);
1781
+
1782
+
while (info == cbinfo &&
1783
+
info->types[QEMU_CLIPBOARD_TYPE_TEXT].available &&
1784
+
info->types[QEMU_CLIPBOARD_TYPE_TEXT].data == NULL) {
1785
+
qemu_mutex_unlock_iothread();
1786
+
qemu_event_wait(&cbevent);
1787
+
qemu_mutex_lock_iothread();
1788
+
}
1789
+
1790
+
if (info == cbinfo) {
1791
+
NSData *data = [[NSData alloc] initWithBytes:info->types[QEMU_CLIPBOARD_TYPE_TEXT].data
1792
+
length:info->types[QEMU_CLIPBOARD_TYPE_TEXT].size];
1793
+
[sender setData:data forType:NSPasteboardTypeString];
1794
+
[data release];
1795
+
}
1796
+
1797
+
qemu_clipboard_info_unref(info);
1798
+
});
1799
+
}
1800
+
1801
+
@end
1802
+
1803
+
static QemuCocoaPasteboardTypeOwner *cbowner;
1804
+
1805
+
static void cocoa_clipboard_notify(Notifier *notifier, void *data);
1806
+
static void cocoa_clipboard_request(QemuClipboardInfo *info,
1807
+
QemuClipboardType type);
1808
+
1809
+
static QemuClipboardPeer cbpeer = {
1810
+
.name = "cocoa",
1811
+
.update = { .notify = cocoa_clipboard_notify },
1812
+
.request = cocoa_clipboard_request
1813
+
};
1814
+
1815
+
static void cocoa_clipboard_notify(Notifier *notifier, void *data)
1816
+
{
1817
+
QemuClipboardInfo *info = data;
1818
+
1819
+
if (info->owner == &cbpeer || info->selection != QEMU_CLIPBOARD_SELECTION_CLIPBOARD) {
1820
+
return;
1821
+
}
1822
+
1823
+
if (info != cbinfo) {
1824
+
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
1825
+
qemu_clipboard_info_unref(cbinfo);
1826
+
cbinfo = qemu_clipboard_info_ref(info);
1827
+
cbchangecount = [[NSPasteboard generalPasteboard] declareTypes:@[NSPasteboardTypeString] owner:cbowner];
1828
+
[pool release];
1829
+
}
1830
+
1831
+
qemu_event_set(&cbevent);
1832
+
}
1833
+
1834
+
static void cocoa_clipboard_request(QemuClipboardInfo *info,
1835
+
QemuClipboardType type)
1836
+
{
1837
+
NSData *text;
1838
+
1839
+
switch (type) {
1840
+
case QEMU_CLIPBOARD_TYPE_TEXT:
1841
+
text = [[NSPasteboard generalPasteboard] dataForType:NSPasteboardTypeString];
1842
+
if (text) {
1843
+
qemu_clipboard_set_data(&cbpeer, info, type,
1844
+
[text length], [text bytes], true);
1845
+
[text release];
1846
+
}
1847
+
break;
1848
+
default:
1849
+
break;
1850
+
}
1851
+
}
1852
+
1761
1853
/*
1762
1854
* The startup process for the OSX/Cocoa UI is complicated, because
1763
1855
* OSX insists that the UI runs on the initial main thread, and so we
@@ -1792,6 +1884,7 @@ static void addRemovableDevicesMenuItems(void)
1792
1884
COCOA_DEBUG("Second thread: calling qemu_main()\n");
1793
1885
status = qemu_main(gArgc, gArgv, *_NSGetEnviron());
1794
1886
COCOA_DEBUG("Second thread: qemu_main() returned, exiting\n");
1887
+
[cbowner release];
1795
1888
exit(status);
1796
1889
}
1797
1890
@@ -1914,6 +2007,18 @@ static void cocoa_refresh(DisplayChangeListener *dcl)
1914
2007
[cocoaView setAbsoluteEnabled:YES];
1915
2008
});
1916
2009
}
2010
+
2011
+
if (cbchangecount != [[NSPasteboard generalPasteboard] changeCount]) {
2012
+
qemu_clipboard_info_unref(cbinfo);
2013
+
cbinfo = qemu_clipboard_info_new(&cbpeer, QEMU_CLIPBOARD_SELECTION_CLIPBOARD);
2014
+
if ([[NSPasteboard generalPasteboard] availableTypeFromArray:@[NSPasteboardTypeString]]) {
2015
+
cbinfo->types[QEMU_CLIPBOARD_TYPE_TEXT].available = true;
2016
+
}
2017
+
qemu_clipboard_update(cbinfo);
2018
+
cbchangecount = [[NSPasteboard generalPasteboard] changeCount];
2019
+
qemu_event_set(&cbevent);
2020
+
}
2021
+
1917
2022
[pool release];
1918
2023
}
1919
2024
@@ -1939,6 +2044,10 @@ static void cocoa_display_init(DisplayState *ds, DisplayOptions *opts)
1939
2044
1940
2045
// register vga output callbacks
1941
2046
register_displaychangelistener(&dcl);
2047
+
2048
+
qemu_event_init(&cbevent, false);
2049
+
cbowner = [[QemuCocoaPasteboardTypeOwner alloc] init];
2050
+
qemu_clipboard_peer_register(&cbpeer);
1942
2051
}
1943
2052
1944
2053
static QemuDisplay qemu_display_cocoa = {
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4