2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 // (This file gets included by juce_linux_NativeCode.cpp, rather than being
27 // compiled on its own).
28 #if JUCE_INCLUDED_FILE
30 //==============================================================================
31 extern Display
* display
;
32 extern Window juce_messageWindowHandle
;
34 namespace ClipboardHelpers
36 static String localClipboardContent
;
37 static Atom atom_UTF8_STRING
;
38 static Atom atom_CLIPBOARD
;
39 static Atom atom_TARGETS
;
41 //==============================================================================
42 static void initSelectionAtoms()
44 static bool isInitialised
= false;
47 atom_UTF8_STRING
= XInternAtom (display
, "UTF8_STRING", False
);
48 atom_CLIPBOARD
= XInternAtom (display
, "CLIPBOARD", False
);
49 atom_TARGETS
= XInternAtom (display
, "TARGETS", False
);
53 //==============================================================================
54 // Read the content of a window property as either a locale-dependent string or an utf8 string
55 // works only for strings shorter than 1000000 bytes
56 static String
readWindowProperty (Window window
, Atom prop
, Atom fmt
)
62 unsigned long numItems
, bytesLeft
;
64 if (XGetWindowProperty (display
, window
, prop
,
65 0L /* offset */, 1000000 /* length (max) */, False
,
66 AnyPropertyType
/* format */,
67 &actualType
, &actualFormat
, &numItems
, &bytesLeft
,
68 (unsigned char**) &clipData
) == Success
)
70 if (actualType
== atom_UTF8_STRING
&& actualFormat
== 8)
71 returnData
= String::fromUTF8 (clipData
, numItems
);
72 else if (actualType
== XA_STRING
&& actualFormat
== 8)
73 returnData
= String (clipData
, numItems
);
75 if (clipData
!= nullptr)
78 jassert (bytesLeft
== 0 || numItems
== 1000000);
81 XDeleteProperty (display
, window
, prop
);
85 //==============================================================================
86 // Send a SelectionRequest to the window owning the selection and waits for its answer (with a timeout) */
87 static bool requestSelectionContent (String
& selectionContent
, Atom selection
, Atom requestedFormat
)
89 Atom property_name
= XInternAtom (display
, "JUCE_SEL", false);
91 // The selection owner will be asked to set the JUCE_SEL property on the
92 // juce_messageWindowHandle with the selection content
93 XConvertSelection (display
, selection
, requestedFormat
, property_name
,
94 juce_messageWindowHandle
, CurrentTime
);
96 int count
= 50; // will wait at most for 200 ms
101 if (XCheckTypedWindowEvent (display
, juce_messageWindowHandle
, SelectionNotify
, &event
))
103 if (event
.xselection
.property
== property_name
)
105 jassert (event
.xselection
.requestor
== juce_messageWindowHandle
);
107 selectionContent
= readWindowProperty (event
.xselection
.requestor
,
108 event
.xselection
.property
,
114 return false; // the format we asked for was denied.. (event.xselection.property == None)
118 // not very elegant.. we could do a select() or something like that...
119 // however clipboard content requesting is inherently slow on x11, it
120 // often takes 50ms or more so...
128 //==============================================================================
129 // Called from the event loop in juce_linux_Messaging in response to SelectionRequest events
130 void juce_handleSelectionRequest (XSelectionRequestEvent
&evt
)
132 ClipboardHelpers::initSelectionAtoms();
134 // the selection content is sent to the target window as a window property
135 XSelectionEvent reply
;
136 reply
.type
= SelectionNotify
;
137 reply
.display
= evt
.display
;
138 reply
.requestor
= evt
.requestor
;
139 reply
.selection
= evt
.selection
;
140 reply
.target
= evt
.target
;
141 reply
.property
= None
; // == "fail"
142 reply
.time
= evt
.time
;
144 HeapBlock
<char> data
;
145 int propertyFormat
= 0, numDataItems
= 0;
147 if (evt
.selection
== XA_PRIMARY
|| evt
.selection
== ClipboardHelpers::atom_CLIPBOARD
)
149 if (evt
.target
== XA_STRING
|| evt
.target
== ClipboardHelpers::atom_UTF8_STRING
)
152 numDataItems
= ClipboardHelpers::localClipboardContent
.getNumBytesAsUTF8() + 1;
153 data
.calloc (numDataItems
+ 1);
154 ClipboardHelpers::localClipboardContent
.copyToUTF8 (data
, numDataItems
);
155 propertyFormat
= 8; // bits/item
157 else if (evt
.target
== ClipboardHelpers::atom_TARGETS
)
159 // another application wants to know what we are able to send
161 propertyFormat
= 32; // atoms are 32-bit
162 data
.calloc (numDataItems
* 4);
163 Atom
* atoms
= reinterpret_cast<Atom
*> (data
.getData());
164 atoms
[0] = ClipboardHelpers::atom_UTF8_STRING
;
165 atoms
[1] = XA_STRING
;
170 DBG ("requested unsupported clipboard");
175 const int maxReasonableSelectionSize
= 1000000;
177 // for very big chunks of data, we should use the "INCR" protocol , which is a pain in the *ss
178 if (evt
.property
!= None
&& numDataItems
< maxReasonableSelectionSize
)
180 XChangeProperty (evt
.display
, evt
.requestor
,
181 evt
.property
, evt
.target
,
182 propertyFormat
/* 8 or 32 */, PropModeReplace
,
183 reinterpret_cast<const unsigned char*> (data
.getData()), numDataItems
);
184 reply
.property
= evt
.property
; // " == success"
188 XSendEvent (evt
.display
, evt
.requestor
, 0, NoEventMask
, (XEvent
*) &reply
);
191 //==============================================================================
192 void SystemClipboard::copyTextToClipboard (const String
& clipText
)
194 ClipboardHelpers::initSelectionAtoms();
195 ClipboardHelpers::localClipboardContent
= clipText
;
197 XSetSelectionOwner (display
, XA_PRIMARY
, juce_messageWindowHandle
, CurrentTime
);
198 XSetSelectionOwner (display
, ClipboardHelpers::atom_CLIPBOARD
, juce_messageWindowHandle
, CurrentTime
);
201 String
SystemClipboard::getTextFromClipboard()
203 ClipboardHelpers::initSelectionAtoms();
205 /* 1) try to read from the "CLIPBOARD" selection first (the "high
206 level" clipboard that is supposed to be filled by ctrl-C
207 etc). When a clipboard manager is running, the content of this
208 selection is preserved even when the original selection owner
211 2) and then try to read from "PRIMARY" selection (the "legacy" selection
212 filled by good old x11 apps such as xterm)
215 Atom selection
= XA_PRIMARY
;
216 Window selectionOwner
= None
;
218 if ((selectionOwner
= XGetSelectionOwner (display
, selection
)) == None
)
220 selection
= ClipboardHelpers::atom_CLIPBOARD
;
221 selectionOwner
= XGetSelectionOwner (display
, selection
);
224 if (selectionOwner
!= None
)
226 if (selectionOwner
== juce_messageWindowHandle
)
228 content
= ClipboardHelpers::localClipboardContent
;
232 // first try: we want an utf8 string
233 bool ok
= ClipboardHelpers::requestSelectionContent (content
, selection
, ClipboardHelpers::atom_UTF8_STRING
);
237 // second chance, ask for a good old locale-dependent string ..
238 ok
= ClipboardHelpers::requestSelectionContent (content
, selection
, XA_STRING
);