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