1 /* 2 * Copyright 2002-2007, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Ingo Weinhold, bonefish@users.sf.net 7 * Gabe Yoder 8 */ 9 10 11 #include "Clipboard.h" 12 #include "ClipboardHandler.h" 13 14 #include <Message.h> 15 #include <RegistrarDefs.h> 16 17 #include <map> 18 #include <string> 19 20 21 using std::map; 22 using std::string; 23 using namespace BPrivate; 24 25 26 /*! 27 \class ClipboardHandler 28 \brief Handles all clipboard related requests. 29 */ 30 31 struct ClipboardHandler::ClipboardMap : map<string, Clipboard*> {}; 32 33 34 // constructor 35 /*! \brief Creates and initializes a ClipboardHandler. 36 */ 37 ClipboardHandler::ClipboardHandler() 38 : BHandler(), 39 fClipboards(new ClipboardMap) 40 { 41 } 42 43 44 // destructor 45 /*! \brief Frees all resources associate with this object. 46 */ 47 ClipboardHandler::~ClipboardHandler() 48 { 49 for (ClipboardMap::iterator it = fClipboards->begin(); 50 it != fClipboards->end(); 51 ++it) 52 delete it->second; 53 } 54 55 56 // MessageReceived 57 /*! \brief Overrides the super class version to handle the clipboard specific 58 messages. 59 \param message The message to be handled 60 */ 61 void 62 ClipboardHandler::MessageReceived(BMessage *message) 63 { 64 const char *name; 65 BMessage reply; 66 switch (message->what) { 67 case B_REG_ADD_CLIPBOARD: 68 { 69 status_t result = B_BAD_VALUE; 70 71 if (message->FindString("name", &name) == B_OK) { 72 if (_GetClipboard(name)) 73 result = B_OK; 74 } 75 76 reply.what = B_REG_RESULT; 77 reply.AddInt32("result", result); 78 message->SendReply(&reply); 79 break; 80 } 81 82 case B_REG_GET_CLIPBOARD_COUNT: 83 { 84 status_t result = B_BAD_VALUE; 85 86 if (message->FindString("name", &name) == B_OK) { 87 if (Clipboard *clipboard = _GetClipboard(name)) { 88 reply.AddInt32("count", clipboard->Count()); 89 result = B_OK; 90 } 91 } 92 93 reply.AddInt32("result", result); 94 reply.what = B_REG_RESULT; 95 message->SendReply(&reply); 96 break; 97 } 98 99 case B_REG_CLIPBOARD_START_WATCHING: 100 { 101 status_t result = B_BAD_VALUE; 102 103 BMessenger target; 104 if (message->FindString("name", &name) == B_OK 105 && message->FindMessenger("target", &target) == B_OK) { 106 Clipboard *clipboard = _GetClipboard(name); 107 if (clipboard && clipboard->AddWatcher(target)) 108 result = B_OK; 109 } 110 111 reply.what = B_REG_RESULT; 112 reply.AddInt32("result", result); 113 message->SendReply(&reply); 114 break; 115 } 116 117 case B_REG_CLIPBOARD_STOP_WATCHING: 118 { 119 status_t result = B_BAD_VALUE; 120 121 BMessenger target; 122 if (message->FindString("name", &name) == B_OK 123 && message->FindMessenger("target", &target) == B_OK) { 124 Clipboard *clipboard = _GetClipboard(name); 125 if (clipboard && clipboard->RemoveWatcher(target)) 126 result = B_OK; 127 } 128 129 reply.what = B_REG_RESULT; 130 reply.AddInt32("result", result); 131 message->SendReply(&reply); 132 break; 133 } 134 135 case B_REG_DOWNLOAD_CLIPBOARD: 136 { 137 status_t result = B_BAD_VALUE; 138 139 if (message->FindString("name", &name) == B_OK) { 140 Clipboard *clipboard = _GetClipboard(name); 141 if (clipboard) { 142 reply.AddMessage("data", clipboard->Data()); 143 reply.AddMessenger("data source", clipboard->DataSource()); 144 reply.AddInt32("count", clipboard->Count()); 145 result = B_OK; 146 } 147 } 148 149 reply.what = B_REG_RESULT; 150 reply.AddInt32("result", result); 151 message->SendReply(&reply); 152 break; 153 } 154 155 case B_REG_UPLOAD_CLIPBOARD: 156 { 157 status_t result = B_BAD_VALUE; 158 159 BMessage data; 160 BMessenger source; 161 if (message->FindString("name", &name) == B_OK 162 && message->FindMessenger("data source", &source) == B_OK 163 && message->FindMessage("data", &data) == B_OK) { 164 Clipboard *clipboard = _GetClipboard(name); 165 if (clipboard) { 166 int32 localCount; 167 bool failIfChanged; 168 if (message->FindInt32("count", &localCount) == B_OK 169 && message->FindBool("fail if changed", &failIfChanged) 170 == B_OK 171 && failIfChanged 172 && localCount != clipboard->Count()) { 173 // atomic support 174 result = B_ERROR; 175 } else { 176 clipboard->SetData(&data, source); 177 result = reply.AddInt32("count", clipboard->Count()); 178 result = B_OK; 179 } 180 } 181 } 182 183 reply.what = B_REG_RESULT; 184 reply.AddInt32("result", result); 185 message->SendReply(&reply); 186 break; 187 } 188 189 default: 190 BHandler::MessageReceived(message); 191 break; 192 } 193 } 194 195 196 /*! \brief Gets the clipboard with the specified name, or adds it, if not yet 197 existent. 198 199 \param name The name of the clipboard to be returned. 200 \return The clipboard with the respective name. 201 */ 202 Clipboard* 203 ClipboardHandler::_GetClipboard(const char *name) 204 { 205 if (!name) 206 name = "system"; 207 208 Clipboard *clipboard = NULL; 209 ClipboardMap::iterator it = fClipboards->find(name); 210 if (it != fClipboards->end()) { 211 clipboard = it->second; 212 } else { 213 clipboard = new Clipboard(name); 214 (*fClipboards)[name] = clipboard; 215 } 216 217 return clipboard; 218 } 219 220