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 = {
0 commit comments