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 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 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 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 167 BClipboard::Unlock() 168 { 169 fLock.Unlock(); 170 } 171 172 173 bool 174 BClipboard::IsLocked() const 175 { 176 return fLock.IsLocked(); 177 } 178 179 180 status_t 181 BClipboard::Clear() 182 { 183 if (!_AssertLocked()) 184 return B_NOT_ALLOWED; 185 186 return fData->MakeEmpty(); 187 } 188 189 190 status_t 191 BClipboard::Commit() 192 { 193 return Commit(false); 194 } 195 196 197 status_t 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 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 237 BClipboard::DataSource() const 238 { 239 return fDataSource; 240 } 241 242 243 BMessage * 244 BClipboard::Data() const 245 { 246 if (!_AssertLocked()) 247 return NULL; 248 249 return fData; 250 } 251 252 253 // #pragma mark - Private methods 254 255 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 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 269 void BClipboard::_ReservedClipboard1() {} 270 void BClipboard::_ReservedClipboard2() {} 271 void BClipboard::_ReservedClipboard3() {} 272 273 274 bool 275 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 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