xref: /haiku/src/kits/app/Clipboard.cpp (revision 93aeb8c3bc3f13cb1f282e3e749258a23790d947)
1 //------------------------------------------------------------------------------
2 //	Copyright (c) 2001-2004, Haiku
3 //
4 //	Permission is hereby granted, free of charge, to any person obtaining a
5 //	copy of this software and associated documentation files (the "Software"),
6 //	to deal in the Software without restriction, including without limitation
7 //	the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 //	and/or sell copies of the Software, and to permit persons to whom the
9 //	Software is furnished to do so, subject to the following conditions:
10 //
11 //	The above copyright notice and this permission notice shall be included in
12 //	all copies or substantial portions of the Software.
13 //
14 //	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 //	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 //	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 //	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 //	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 //	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 //	DEALINGS IN THE SOFTWARE.
21 //
22 //	File Name:		Clipboard.cpp
23 //	Author:			Gabe Yoder (gyoder@stny.rr.com)
24 //	Description:	BClipboard provides an interface to a system-wide clipboard
25 //                  storage area.
26 //------------------------------------------------------------------------------
27 
28 // Standard Includes -----------------------------------------------------------
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 
33 // System Includes -------------------------------------------------------------
34 #include <Clipboard.h>
35 #include <Application.h>
36 #include <RegistrarDefs.h>
37 #include <RosterPrivate.h>
38 
39 #include <ClipboardPrivate.h>
40 
41 // Globals ---------------------------------------------------------------------
42 #ifdef RUN_WITHOUT_REGISTRAR
43 	static BClipboard sClipboard(NULL);
44 	BClipboard *be_clipboard = &sClipboard;
45 #else
46 	BClipboard *be_clipboard = NULL;
47 #endif
48 
49 
50 using namespace BPrivate;
51 
52 
53 BClipboard::BClipboard(const char *name, bool transient)
54 {
55 	if (name != NULL)
56 		fName = strdup(name);
57 	else
58 		fName = strdup("system");
59 
60 	fData = new BMessage();
61 	fCount = 0;
62 
63 	BMessage message(B_REG_GET_CLIPBOARD_MESSENGER), reply;
64 	if (BRoster::Private().SendTo(&message, &reply, false) == B_OK
65 		&& reply.what == B_REG_SUCCESS
66 		&& reply.FindMessenger("messenger", &fClipHandler) == B_OK) {
67 		BMessage handlerMessage(B_REG_ADD_CLIPBOARD), handlerReply;
68 		int32 result;
69 		if (handlerMessage.AddString("name", fName) == B_OK
70 			&& fClipHandler.SendMessage(&handlerMessage, &handlerReply) == B_OK)
71 			handlerReply.FindInt32("result", &result);
72 	}
73 }
74 
75 
76 BClipboard::~BClipboard()
77 {
78 	free(fName);
79 	delete fData;
80 }
81 
82 
83 const char *
84 BClipboard::Name() const
85 {
86 	return (const char *)fName;
87 }
88 
89 /*!	\brief Returns the (locally cached) number of commits to the clipboard.
90 
91 	The returned value is the number of successful Commit() invocations for
92 	the clipboard represented by this object, either invoked on this object
93 	or another (even from another application). This method returns a locally
94 	cached value, which might already be obsolete. For an up-to-date value
95 	SystemCount() can be invoked.
96 
97 	\return The number of commits to the clipboard.
98 */
99 uint32
100 BClipboard::LocalCount() const
101 {
102 	return fCount;
103 }
104 
105 /*!	\brief Returns the number of commits to the clipboard.
106 
107 	The returned value is the number of successful Commit() invocations for
108 	the clipboard represented by this object, either invoked on this object
109 	or another (even from another application). This method retrieves the
110 	value directly from the system service managing the clipboards, so it is
111 	more expensive, but more up-to-date than LocalCount(), which returns a
112 	locally cached value.
113 
114 	\return The number of commits to the clipboard.
115 */
116 uint32
117 BClipboard::SystemCount() const
118 {
119 	int32 value;
120 	BMessage message(B_REG_GET_CLIPBOARD_COUNT), reply;
121 	if (message.AddString("name", fName) == B_OK
122 		&& fClipHandler.SendMessage(&message, &reply) == B_OK
123 		&& reply.FindInt32("count", &value) == B_OK)
124 		return (uint32)value;
125 
126 	return 0;
127 }
128 
129 
130 status_t
131 BClipboard::StartWatching(BMessenger target)
132 {
133 	BMessage message(B_REG_CLIPBOARD_START_WATCHING), reply;
134 	if (message.AddString("name", fName) == B_OK
135 		&& message.AddMessenger("target", target) == B_OK
136 		&& fClipHandler.SendMessage(&message, &reply) == B_OK) {
137 		int32 result;
138 		reply.FindInt32("result", &result);
139 		return result;
140 	}
141 	return B_ERROR;
142 }
143 
144 
145 status_t
146 BClipboard::StopWatching(BMessenger target)
147 {
148 	BMessage message(B_REG_CLIPBOARD_STOP_WATCHING), reply;
149 	if (message.AddString("name", fName) == B_OK
150 		&& message.AddMessenger("target", target) == B_OK
151 		&& fClipHandler.SendMessage(&message, &reply) == B_OK) {
152 		int32 result;
153 		reply.FindInt32("result", &result);
154 		return result;
155 	}
156 	return B_ERROR;
157 }
158 
159 
160 bool
161 BClipboard::Lock()
162 {
163 	// Will this work correctly if clipboard is deleted while still waiting on
164 	// fLock.Lock() ?
165 	bool locked = fLock.Lock();
166 
167 #ifndef RUN_WITHOUT_REGISTRAR
168 	if (locked && DownloadFromSystem() != B_OK) {
169 		locked = false;
170 		fLock.Unlock();
171 	}
172 #endif
173 
174 	return locked;
175 }
176 
177 
178 void
179 BClipboard::Unlock()
180 {
181 	fLock.Unlock();
182 }
183 
184 
185 bool
186 BClipboard::IsLocked() const
187 {
188 	return fLock.IsLocked();
189 }
190 
191 
192 status_t
193 BClipboard::Clear()
194 {
195 	if (!AssertLocked())
196 		return B_NOT_ALLOWED;
197 
198 	return fData->MakeEmpty();
199 }
200 
201 
202 status_t
203 BClipboard::Commit()
204 {
205 	if (!AssertLocked())
206 		return B_NOT_ALLOWED;
207 
208 	return UploadToSystem();
209 }
210 
211 
212 status_t
213 BClipboard::Revert()
214 {
215 	if (!AssertLocked())
216 		return B_NOT_ALLOWED;
217 
218 	status_t status = fData->MakeEmpty();
219 	if (status == B_OK)
220 		status = DownloadFromSystem();
221 
222 	return status;
223 }
224 
225 
226 BMessenger
227 BClipboard::DataSource() const
228 {
229 	return fDataSource;
230 }
231 
232 
233 BMessage *
234 BClipboard::Data() const
235 {
236 	if (!AssertLocked())
237 		return NULL;
238 
239     return fData;
240 }
241 
242 
243 //	#pragma mark -
244 //	Private methods
245 
246 
247 BClipboard::BClipboard(const BClipboard &)
248 {
249 	// This is private, and I don't use it, so I'm not going to implement it
250 }
251 
252 
253 BClipboard & BClipboard::operator=(const BClipboard &)
254 {
255 	// This is private, and I don't use it, so I'm not going to implement it
256 	return *this;
257 }
258 
259 
260 void BClipboard::_ReservedClipboard1() {}
261 void BClipboard::_ReservedClipboard2() {}
262 void BClipboard::_ReservedClipboard3() {}
263 
264 
265 bool
266 BClipboard::AssertLocked() const
267 {
268 	// This function is for jumping to the debugger if not locked
269 	if (!fLock.IsLocked()) {
270 		debugger("The clipboard must be locked before proceeding.");
271 		return false;
272 	}
273 	return true;
274 }
275 
276 
277 status_t
278 BClipboard::DownloadFromSystem(bool force)
279 {
280 	// Apparently, the force paramater was used in some sort of
281 	// optimization in R5. Currently, we ignore it.
282 	BMessage message(B_REG_DOWNLOAD_CLIPBOARD), reply;
283 	if (message.AddString("name", fName) == B_OK
284 		&& fClipHandler.SendMessage(&message, &reply) == B_OK
285 		&& reply.FindMessage("data", fData) == B_OK
286 		&& reply.FindMessenger("data source", &fDataSource) == B_OK
287 		&& reply.FindInt32("count", (int32 *)&fCount) == B_OK)
288 		return B_OK;
289 
290 	return B_ERROR;
291 }
292 
293 
294 status_t
295 BClipboard::UploadToSystem()
296 {
297 	BMessage message(B_REG_UPLOAD_CLIPBOARD), reply;
298 	if (message.AddString("name", fName) == B_OK
299 		&& message.AddMessage("data", fData) == B_OK
300 		&& message.AddMessenger("data source", be_app_messenger) == B_OK
301 		&& fClipHandler.SendMessage(&message, &reply) == B_OK
302 		&& reply.FindInt32("count", (int32 *)&fCount) == B_OK) {
303 		return B_OK;
304 	}
305 	return B_ERROR;
306 }
307 
308 // init_clipboard
309 /*!	\brief Initializes the global \c be_clipboard.
310 
311 	Invoked at libbe initialization time.
312 */
313 void
314 BPrivate::init_clipboard()
315 {
316 	be_clipboard = new BClipboard(NULL);
317 }
318