xref: /haiku/src/kits/app/Clipboard.cpp (revision d3d8b26997fac34a84981e6d2b649521de2cc45a)
1 /*
2  * Copyright 2001-2005, 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 	if (!AssertLocked())
187 		return B_NOT_ALLOWED;
188 
189 	return UploadToSystem();
190 }
191 
192 
193 status_t
194 BClipboard::Revert()
195 {
196 	if (!AssertLocked())
197 		return B_NOT_ALLOWED;
198 
199 	status_t status = fData->MakeEmpty();
200 	if (status == B_OK)
201 		status = DownloadFromSystem();
202 
203 	return status;
204 }
205 
206 
207 BMessenger
208 BClipboard::DataSource() const
209 {
210 	return fDataSource;
211 }
212 
213 
214 BMessage *
215 BClipboard::Data() const
216 {
217 	if (!AssertLocked())
218 		return NULL;
219 
220     return fData;
221 }
222 
223 
224 //	#pragma mark - Private methods
225 
226 
227 BClipboard::BClipboard(const BClipboard &)
228 {
229 	// This is private, and I don't use it, so I'm not going to implement it
230 }
231 
232 
233 BClipboard & BClipboard::operator=(const BClipboard &)
234 {
235 	// This is private, and I don't use it, so I'm not going to implement it
236 	return *this;
237 }
238 
239 
240 void BClipboard::_ReservedClipboard1() {}
241 void BClipboard::_ReservedClipboard2() {}
242 void BClipboard::_ReservedClipboard3() {}
243 
244 
245 bool
246 BClipboard::AssertLocked() const
247 {
248 	// This function is for jumping to the debugger if not locked
249 	if (!fLock.IsLocked()) {
250 		debugger("The clipboard must be locked before proceeding.");
251 		return false;
252 	}
253 	return true;
254 }
255 
256 
257 status_t
258 BClipboard::DownloadFromSystem(bool force)
259 {
260 	// Apparently, the force paramater was used in some sort of
261 	// optimization in R5. Currently, we ignore it.
262 	BMessage message(B_REG_DOWNLOAD_CLIPBOARD), reply;
263 	if (message.AddString("name", fName) == B_OK
264 		&& fClipHandler.SendMessage(&message, &reply) == B_OK
265 		&& reply.FindMessage("data", fData) == B_OK
266 		&& reply.FindMessenger("data source", &fDataSource) == B_OK
267 		&& reply.FindInt32("count", (int32 *)&fCount) == B_OK)
268 		return B_OK;
269 
270 	return B_ERROR;
271 }
272 
273 
274 status_t
275 BClipboard::UploadToSystem()
276 {
277 	BMessage message(B_REG_UPLOAD_CLIPBOARD), reply;
278 	if (message.AddString("name", fName) == B_OK
279 		&& message.AddMessage("data", fData) == B_OK
280 		&& message.AddMessenger("data source", be_app_messenger) == B_OK
281 		&& fClipHandler.SendMessage(&message, &reply) == B_OK
282 		&& reply.FindInt32("count", (int32 *)&fCount) == B_OK) {
283 		return B_OK;
284 	}
285 	return B_ERROR;
286 }
287 
288 
289 //	#pragma mark -
290 
291 
292 /*!	\brief Initializes the global \c be_clipboard.
293 
294 	Invoked at libbe initialization time.
295 */
296 void
297 BPrivate::init_clipboard()
298 {
299 	be_clipboard = new BClipboard(NULL);
300 }
301