xref: /haiku/src/kits/app/Clipboard.cpp (revision b289aaf66bbf6e173aa90fa194fc256965f1b34d)
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 	BMessage message(B_REG_CLIPBOARD_START_WATCHING), reply;
116 	if (message.AddString("name", fName) == B_OK
117 		&& message.AddMessenger("target", target) == B_OK
118 		&& fClipHandler.SendMessage(&message, &reply) == B_OK) {
119 		int32 result;
120 		reply.FindInt32("result", &result);
121 		return result;
122 	}
123 	return B_ERROR;
124 }
125 
126 
127 status_t
128 BClipboard::StopWatching(BMessenger target)
129 {
130 	BMessage message(B_REG_CLIPBOARD_STOP_WATCHING), reply;
131 	if (message.AddString("name", fName) == B_OK
132 		&& message.AddMessenger("target", target) == B_OK
133 		&& fClipHandler.SendMessage(&message, &reply) == B_OK) {
134 		int32 result;
135 		if (reply.FindInt32("result", &result) == B_OK)
136 			return result;
137 	}
138 	return B_ERROR;
139 }
140 
141 
142 bool
143 BClipboard::Lock()
144 {
145 	// Will this work correctly if clipboard is deleted while still waiting on
146 	// fLock.Lock() ?
147 	bool locked = fLock.Lock();
148 
149 #ifndef RUN_WITHOUT_REGISTRAR
150 	if (locked && _DownloadFromSystem() != B_OK) {
151 		locked = false;
152 		fLock.Unlock();
153 	}
154 #endif
155 
156 	return locked;
157 }
158 
159 
160 void
161 BClipboard::Unlock()
162 {
163 	fLock.Unlock();
164 }
165 
166 
167 bool
168 BClipboard::IsLocked() const
169 {
170 	return fLock.IsLocked();
171 }
172 
173 
174 status_t
175 BClipboard::Clear()
176 {
177 	if (!_AssertLocked())
178 		return B_NOT_ALLOWED;
179 
180 	return fData->MakeEmpty();
181 }
182 
183 
184 status_t
185 BClipboard::Commit()
186 {
187 	return Commit(false);
188 }
189 
190 
191 status_t
192 BClipboard::Commit(bool failIfChanged)
193 {
194 	if (!_AssertLocked())
195 		return B_NOT_ALLOWED;
196 
197 	status_t status = B_ERROR;
198 	BMessage message(B_REG_UPLOAD_CLIPBOARD), reply;
199 	if (message.AddString("name", fName) == B_OK
200 		&& message.AddMessage("data", fData) == B_OK
201 		&& message.AddMessenger("data source", be_app_messenger) == B_OK
202 		&& message.AddInt32("count", fCount) == B_OK
203 		&& message.AddBool("fail if changed", failIfChanged) == B_OK)
204 		status = fClipHandler.SendMessage(&message, &reply);
205 
206 	if (status == B_OK) {
207 		int32 count;
208 		if (reply.FindInt32("count", &count) == B_OK)
209 			fCount = count;
210 	}
211 
212 	return status;
213 }
214 
215 
216 status_t
217 BClipboard::Revert()
218 {
219 	if (!_AssertLocked())
220 		return B_NOT_ALLOWED;
221 
222 	status_t status = fData->MakeEmpty();
223 	if (status == B_OK)
224 		status = _DownloadFromSystem();
225 
226 	return status;
227 }
228 
229 
230 BMessenger
231 BClipboard::DataSource() const
232 {
233 	return fDataSource;
234 }
235 
236 
237 BMessage *
238 BClipboard::Data() const
239 {
240 	if (!_AssertLocked())
241 		return NULL;
242 
243     return fData;
244 }
245 
246 
247 //	#pragma mark - Private methods
248 
249 
250 BClipboard::BClipboard(const BClipboard &)
251 {
252 	// This is private, and I don't use it, so I'm not going to implement it
253 }
254 
255 
256 BClipboard & BClipboard::operator=(const BClipboard &)
257 {
258 	// This is private, and I don't use it, so I'm not going to implement it
259 	return *this;
260 }
261 
262 
263 void BClipboard::_ReservedClipboard1() {}
264 void BClipboard::_ReservedClipboard2() {}
265 void BClipboard::_ReservedClipboard3() {}
266 
267 
268 bool
269 BClipboard::_AssertLocked() const
270 {
271 	// This function is for jumping to the debugger if not locked
272 	if (!fLock.IsLocked()) {
273 		debugger("The clipboard must be locked before proceeding.");
274 		return false;
275 	}
276 	return true;
277 }
278 
279 
280 status_t
281 BClipboard::_DownloadFromSystem(bool force)
282 {
283 	// Apparently, the force paramater was used in some sort of
284 	// optimization in R5. Currently, we ignore it.
285 	BMessage message(B_REG_DOWNLOAD_CLIPBOARD), reply;
286 	if (message.AddString("name", fName) == B_OK
287 		&& fClipHandler.SendMessage(&message, &reply) == B_OK
288 		&& reply.FindMessage("data", fData) == B_OK
289 		&& reply.FindMessenger("data source", &fDataSource) == B_OK
290 		&& reply.FindInt32("count", (int32 *)&fCount) == B_OK)
291 		return B_OK;
292 
293 	return B_ERROR;
294 }
295