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
28using namespace BPrivate;
29
30
31BClipboard::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
56BClipboard::~BClipboard()
57{
58	free(fName);
59	delete fData;
60}
61
62
63const char *
64BClipboard::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*/
80uint32
81BClipboard::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*/
98uint32
99BClipboard::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
112status_t
113BClipboard::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
130status_t
131BClipboard::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
148bool
149BClipboard::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
166void
167BClipboard::Unlock()
168{
169	fLock.Unlock();
170}
171
172
173bool
174BClipboard::IsLocked() const
175{
176	return fLock.IsLocked();
177}
178
179
180status_t
181BClipboard::Clear()
182{
183	if (!_AssertLocked())
184		return B_NOT_ALLOWED;
185
186	return fData->MakeEmpty();
187}
188
189
190status_t
191BClipboard::Commit()
192{
193	return Commit(false);
194}
195
196
197status_t
198BClipboard::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
222status_t
223BClipboard::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
236BMessenger
237BClipboard::DataSource() const
238{
239	return fDataSource;
240}
241
242
243BMessage *
244BClipboard::Data() const
245{
246	if (!_AssertLocked())
247		return NULL;
248
249    return fData;
250}
251
252
253//	#pragma mark - Private methods
254
255
256BClipboard::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
262BClipboard & 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
269void BClipboard::_ReservedClipboard1() {}
270void BClipboard::_ReservedClipboard2() {}
271void BClipboard::_ReservedClipboard3() {}
272
273
274bool
275BClipboard::_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
286status_t
287BClipboard::_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) == 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