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