1 //------------------------------------------------------------------------------ 2 // Copyright (c) 2001-2004, Haiku 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a 5 // copy of this software and associated documentation files (the "Software"), 6 // to deal in the Software without restriction, including without limitation 7 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 // and/or sell copies of the Software, and to permit persons to whom the 9 // Software is furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 // DEALINGS IN THE SOFTWARE. 21 // 22 // File Name: Clipboard.cpp 23 // Author: Gabe Yoder (gyoder@stny.rr.com) 24 // Description: BClipboard provides an interface to a system-wide clipboard 25 // storage area. 26 //------------------------------------------------------------------------------ 27 28 // Standard Includes ----------------------------------------------------------- 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 33 // System Includes ------------------------------------------------------------- 34 #include <Clipboard.h> 35 #include <Application.h> 36 #include <RegistrarDefs.h> 37 #include <RosterPrivate.h> 38 39 #include <ClipboardPrivate.h> 40 41 // Globals --------------------------------------------------------------------- 42 #ifdef RUN_WITHOUT_REGISTRAR 43 static BClipboard sClipboard(NULL); 44 BClipboard *be_clipboard = &sClipboard; 45 #else 46 BClipboard *be_clipboard = NULL; 47 #endif 48 49 50 using namespace BPrivate; 51 52 53 BClipboard::BClipboard(const char *name, bool transient) 54 { 55 if (name != NULL) 56 fName = strdup(name); 57 else 58 fName = strdup("system"); 59 60 fData = new BMessage(); 61 fCount = 0; 62 63 BMessage message(B_REG_GET_CLIPBOARD_MESSENGER), reply; 64 if (BRoster::Private().SendTo(&message, &reply, false) == B_OK 65 && reply.what == B_REG_SUCCESS 66 && reply.FindMessenger("messenger", &fClipHandler) == B_OK) { 67 BMessage handlerMessage(B_REG_ADD_CLIPBOARD), handlerReply; 68 int32 result; 69 if (handlerMessage.AddString("name", fName) == B_OK 70 && fClipHandler.SendMessage(&handlerMessage, &handlerReply) == B_OK) 71 handlerReply.FindInt32("result", &result); 72 } 73 } 74 75 76 BClipboard::~BClipboard() 77 { 78 free(fName); 79 delete fData; 80 } 81 82 83 const char * 84 BClipboard::Name() const 85 { 86 return (const char *)fName; 87 } 88 89 /*! \brief Returns the (locally cached) number of commits to the clipboard. 90 91 The returned value is the number of successful Commit() invocations for 92 the clipboard represented by this object, either invoked on this object 93 or another (even from another application). This method returns a locally 94 cached value, which might already be obsolete. For an up-to-date value 95 SystemCount() can be invoked. 96 97 \return The number of commits to the clipboard. 98 */ 99 uint32 100 BClipboard::LocalCount() const 101 { 102 return fCount; 103 } 104 105 /*! \brief Returns the number of commits to the clipboard. 106 107 The returned value is the number of successful Commit() invocations for 108 the clipboard represented by this object, either invoked on this object 109 or another (even from another application). This method retrieves the 110 value directly from the system service managing the clipboards, so it is 111 more expensive, but more up-to-date than LocalCount(), which returns a 112 locally cached value. 113 114 \return The number of commits to the clipboard. 115 */ 116 uint32 117 BClipboard::SystemCount() const 118 { 119 int32 value; 120 BMessage message(B_REG_GET_CLIPBOARD_COUNT), reply; 121 if (message.AddString("name", fName) == B_OK 122 && fClipHandler.SendMessage(&message, &reply) == B_OK 123 && reply.FindInt32("count", &value) == B_OK) 124 return (uint32)value; 125 126 return 0; 127 } 128 129 130 status_t 131 BClipboard::StartWatching(BMessenger target) 132 { 133 BMessage message(B_REG_CLIPBOARD_START_WATCHING), reply; 134 if (message.AddString("name", fName) == B_OK 135 && message.AddMessenger("target", target) == B_OK 136 && fClipHandler.SendMessage(&message, &reply) == B_OK) { 137 int32 result; 138 reply.FindInt32("result", &result); 139 return result; 140 } 141 return B_ERROR; 142 } 143 144 145 status_t 146 BClipboard::StopWatching(BMessenger target) 147 { 148 BMessage message(B_REG_CLIPBOARD_STOP_WATCHING), reply; 149 if (message.AddString("name", fName) == B_OK 150 && message.AddMessenger("target", target) == B_OK 151 && fClipHandler.SendMessage(&message, &reply) == B_OK) { 152 int32 result; 153 reply.FindInt32("result", &result); 154 return result; 155 } 156 return B_ERROR; 157 } 158 159 160 bool 161 BClipboard::Lock() 162 { 163 // Will this work correctly if clipboard is deleted while still waiting on 164 // fLock.Lock() ? 165 bool locked = fLock.Lock(); 166 167 #ifndef RUN_WITHOUT_REGISTRAR 168 if (locked && DownloadFromSystem() != B_OK) { 169 locked = false; 170 fLock.Unlock(); 171 } 172 #endif 173 174 return locked; 175 } 176 177 178 void 179 BClipboard::Unlock() 180 { 181 fLock.Unlock(); 182 } 183 184 185 bool 186 BClipboard::IsLocked() const 187 { 188 return fLock.IsLocked(); 189 } 190 191 192 status_t 193 BClipboard::Clear() 194 { 195 if (!AssertLocked()) 196 return B_NOT_ALLOWED; 197 198 return fData->MakeEmpty(); 199 } 200 201 202 status_t 203 BClipboard::Commit() 204 { 205 if (!AssertLocked()) 206 return B_NOT_ALLOWED; 207 208 return UploadToSystem(); 209 } 210 211 212 status_t 213 BClipboard::Revert() 214 { 215 if (!AssertLocked()) 216 return B_NOT_ALLOWED; 217 218 status_t status = fData->MakeEmpty(); 219 if (status == B_OK) 220 status = DownloadFromSystem(); 221 222 return status; 223 } 224 225 226 BMessenger 227 BClipboard::DataSource() const 228 { 229 return fDataSource; 230 } 231 232 233 BMessage * 234 BClipboard::Data() const 235 { 236 if (!AssertLocked()) 237 return NULL; 238 239 return fData; 240 } 241 242 243 // #pragma mark - 244 // Private methods 245 246 247 BClipboard::BClipboard(const BClipboard &) 248 { 249 // This is private, and I don't use it, so I'm not going to implement it 250 } 251 252 253 BClipboard & BClipboard::operator=(const BClipboard &) 254 { 255 // This is private, and I don't use it, so I'm not going to implement it 256 return *this; 257 } 258 259 260 void BClipboard::_ReservedClipboard1() {} 261 void BClipboard::_ReservedClipboard2() {} 262 void BClipboard::_ReservedClipboard3() {} 263 264 265 bool 266 BClipboard::AssertLocked() const 267 { 268 // This function is for jumping to the debugger if not locked 269 if (!fLock.IsLocked()) { 270 debugger("The clipboard must be locked before proceeding."); 271 return false; 272 } 273 return true; 274 } 275 276 277 status_t 278 BClipboard::DownloadFromSystem(bool force) 279 { 280 // Apparently, the force paramater was used in some sort of 281 // optimization in R5. Currently, we ignore it. 282 BMessage message(B_REG_DOWNLOAD_CLIPBOARD), reply; 283 if (message.AddString("name", fName) == B_OK 284 && fClipHandler.SendMessage(&message, &reply) == B_OK 285 && reply.FindMessage("data", fData) == B_OK 286 && reply.FindMessenger("data source", &fDataSource) == B_OK 287 && reply.FindInt32("count", (int32 *)&fCount) == B_OK) 288 return B_OK; 289 290 return B_ERROR; 291 } 292 293 294 status_t 295 BClipboard::UploadToSystem() 296 { 297 BMessage message(B_REG_UPLOAD_CLIPBOARD), reply; 298 if (message.AddString("name", fName) == B_OK 299 && message.AddMessage("data", fData) == B_OK 300 && message.AddMessenger("data source", be_app_messenger) == B_OK 301 && fClipHandler.SendMessage(&message, &reply) == B_OK 302 && reply.FindInt32("count", (int32 *)&fCount) == B_OK) { 303 return B_OK; 304 } 305 return B_ERROR; 306 } 307 308 // init_clipboard 309 /*! \brief Initializes the global \c be_clipboard. 310 311 Invoked at libbe initialization time. 312 */ 313 void 314 BPrivate::init_clipboard() 315 { 316 be_clipboard = new BClipboard(NULL); 317 } 318