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
BClipboard(const char * name,bool transient)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
~BClipboard()56 BClipboard::~BClipboard()
57 {
58 free(fName);
59 delete fData;
60 }
61
62
63 const char *
Name() const64 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
LocalCount() const81 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
SystemCount() const99 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
StartWatching(BMessenger target)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
StopWatching(BMessenger target)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
Lock()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
Unlock()167 BClipboard::Unlock()
168 {
169 fLock.Unlock();
170 }
171
172
173 bool
IsLocked() const174 BClipboard::IsLocked() const
175 {
176 return fLock.IsLocked();
177 }
178
179
180 status_t
Clear()181 BClipboard::Clear()
182 {
183 if (!_AssertLocked())
184 return B_NOT_ALLOWED;
185
186 return fData->MakeEmpty();
187 }
188
189
190 status_t
Commit()191 BClipboard::Commit()
192 {
193 return Commit(false);
194 }
195
196
197 status_t
Commit(bool failIfChanged)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
Revert()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
DataSource() const237 BClipboard::DataSource() const
238 {
239 return fDataSource;
240 }
241
242
243 BMessage *
Data() const244 BClipboard::Data() const
245 {
246 if (!_AssertLocked())
247 return NULL;
248
249 return fData;
250 }
251
252
253 // #pragma mark - Private methods
254
255
BClipboard(const BClipboard &)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
operator =(const BClipboard &)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
_ReservedClipboard1()269 void BClipboard::_ReservedClipboard1() {}
_ReservedClipboard2()270 void BClipboard::_ReservedClipboard2() {}
_ReservedClipboard3()271 void BClipboard::_ReservedClipboard3() {}
272
273
274 bool
_AssertLocked() const275 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
_DownloadFromSystem(bool force)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