xref: /haiku/src/servers/registrar/ClipboardHandler.cpp (revision fc7456e9b1ec38c941134ed6d01c438cf289381e)
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 			result = message->SendReply(&reply);
152 			if (result != B_OK) {
153 				reply.MakeEmpty();
154 				reply.what = B_REG_RESULT;
155 				reply.AddInt32("result", result);
156 				message->SendReply(&reply);
157 			}
158 			break;
159 		}
160 
161 		case B_REG_UPLOAD_CLIPBOARD:
162 		{
163 			status_t result = B_BAD_VALUE;
164 
165 			BMessage data;
166 			BMessenger source;
167 			if (message->FindString("name", &name) == B_OK
168 				&& message->FindMessenger("data source", &source) == B_OK
169 				&& message->FindMessage("data", &data) == B_OK) {
170 				Clipboard *clipboard = _GetClipboard(name);
171 				if (clipboard) {
172 					int32 localCount;
173 					bool failIfChanged;
174 					if (message->FindInt32("count", &localCount) == B_OK
175 						&& message->FindBool("fail if changed", &failIfChanged)
176 							== B_OK
177 						&& failIfChanged
178 						&& localCount != clipboard->Count()) {
179 						// atomic support
180 						result = B_ERROR;
181 					} else {
182 						clipboard->SetData(&data, source);
183 						result = reply.AddInt32("count", clipboard->Count());
184 						result = B_OK;
185 					}
186 				}
187 			}
188 
189 			reply.what = B_REG_RESULT;
190 			reply.AddInt32("result", result);
191 			message->SendReply(&reply);
192 			break;
193 		}
194 
195 		default:
196 			BHandler::MessageReceived(message);
197 			break;
198 	}
199 }
200 
201 
202 /*!	\brief Gets the clipboard with the specified name, or adds it, if not yet
203 		   existent.
204 
205 	\param name The name of the clipboard to be returned.
206 	\return The clipboard with the respective name.
207 */
208 Clipboard*
209 ClipboardHandler::_GetClipboard(const char *name)
210 {
211 	if (!name)
212 		name = "system";
213 
214 	Clipboard *clipboard = NULL;
215 	ClipboardMap::iterator it = fClipboards->find(name);
216 	if (it != fClipboards->end()) {
217 		clipboard = it->second;
218 	} else {
219 		clipboard = new Clipboard(name);
220 		(*fClipboards)[name] = clipboard;
221 	}
222 
223 	return clipboard;
224 }
225 
226