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