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 BMessage message(B_REG_CLIPBOARD_START_WATCHING), reply; 116 if (message.AddString("name", fName) == B_OK 117 && message.AddMessenger("target", target) == B_OK 118 && fClipHandler.SendMessage(&message, &reply) == B_OK) { 119 int32 result; 120 reply.FindInt32("result", &result); 121 return result; 122 } 123 return B_ERROR; 124 } 125 126 127 status_t 128 BClipboard::StopWatching(BMessenger target) 129 { 130 BMessage message(B_REG_CLIPBOARD_STOP_WATCHING), reply; 131 if (message.AddString("name", fName) == B_OK 132 && message.AddMessenger("target", target) == B_OK 133 && fClipHandler.SendMessage(&message, &reply) == B_OK) { 134 int32 result; 135 if (reply.FindInt32("result", &result) == B_OK) 136 return result; 137 } 138 return B_ERROR; 139 } 140 141 142 bool 143 BClipboard::Lock() 144 { 145 // Will this work correctly if clipboard is deleted while still waiting on 146 // fLock.Lock() ? 147 bool locked = fLock.Lock(); 148 149 #ifndef RUN_WITHOUT_REGISTRAR 150 if (locked && _DownloadFromSystem() != B_OK) { 151 locked = false; 152 fLock.Unlock(); 153 } 154 #endif 155 156 return locked; 157 } 158 159 160 void 161 BClipboard::Unlock() 162 { 163 fLock.Unlock(); 164 } 165 166 167 bool 168 BClipboard::IsLocked() const 169 { 170 return fLock.IsLocked(); 171 } 172 173 174 status_t 175 BClipboard::Clear() 176 { 177 if (!_AssertLocked()) 178 return B_NOT_ALLOWED; 179 180 return fData->MakeEmpty(); 181 } 182 183 184 status_t 185 BClipboard::Commit() 186 { 187 return Commit(false); 188 } 189 190 191 status_t 192 BClipboard::Commit(bool failIfChanged) 193 { 194 if (!_AssertLocked()) 195 return B_NOT_ALLOWED; 196 197 status_t status = B_ERROR; 198 BMessage message(B_REG_UPLOAD_CLIPBOARD), reply; 199 if (message.AddString("name", fName) == B_OK 200 && message.AddMessage("data", fData) == B_OK 201 && message.AddMessenger("data source", be_app_messenger) == B_OK 202 && message.AddInt32("count", fCount) == B_OK 203 && message.AddBool("fail if changed", failIfChanged) == B_OK) 204 status = fClipHandler.SendMessage(&message, &reply); 205 206 if (status == B_OK) { 207 int32 count; 208 if (reply.FindInt32("count", &count) == B_OK) 209 fCount = count; 210 } 211 212 return status; 213 } 214 215 216 status_t 217 BClipboard::Revert() 218 { 219 if (!_AssertLocked()) 220 return B_NOT_ALLOWED; 221 222 status_t status = fData->MakeEmpty(); 223 if (status == B_OK) 224 status = _DownloadFromSystem(); 225 226 return status; 227 } 228 229 230 BMessenger 231 BClipboard::DataSource() const 232 { 233 return fDataSource; 234 } 235 236 237 BMessage * 238 BClipboard::Data() const 239 { 240 if (!_AssertLocked()) 241 return NULL; 242 243 return fData; 244 } 245 246 247 // #pragma mark - Private methods 248 249 250 BClipboard::BClipboard(const BClipboard &) 251 { 252 // This is private, and I don't use it, so I'm not going to implement it 253 } 254 255 256 BClipboard & BClipboard::operator=(const BClipboard &) 257 { 258 // This is private, and I don't use it, so I'm not going to implement it 259 return *this; 260 } 261 262 263 void BClipboard::_ReservedClipboard1() {} 264 void BClipboard::_ReservedClipboard2() {} 265 void BClipboard::_ReservedClipboard3() {} 266 267 268 bool 269 BClipboard::_AssertLocked() const 270 { 271 // This function is for jumping to the debugger if not locked 272 if (!fLock.IsLocked()) { 273 debugger("The clipboard must be locked before proceeding."); 274 return false; 275 } 276 return true; 277 } 278 279 280 status_t 281 BClipboard::_DownloadFromSystem(bool force) 282 { 283 // Apparently, the force paramater was used in some sort of 284 // optimization in R5. Currently, we ignore it. 285 BMessage message(B_REG_DOWNLOAD_CLIPBOARD), reply; 286 if (message.AddString("name", fName) == B_OK 287 && fClipHandler.SendMessage(&message, &reply) == B_OK 288 && reply.FindMessage("data", fData) == B_OK 289 && reply.FindMessenger("data source", &fDataSource) == B_OK 290 && reply.FindInt32("count", (int32 *)&fCount) == B_OK) 291 return B_OK; 292 293 return B_ERROR; 294 } 295