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