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