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
20using std::map;
21using std::string;
22using namespace BPrivate;
23
24/*!
25	\class ClipboardHandler
26	\brief Handles all clipboard related requests.
27*/
28
29struct ClipboardHandler::ClipboardMap : map<string, Clipboard*> {};
30
31// constructor
32/*!	\brief Creates and initializes a ClipboardHandler.
33*/
34ClipboardHandler::ClipboardHandler()
35				: BHandler(),
36				  fClipboards(new ClipboardMap)
37{
38}
39
40// destructor
41/*!	\brief Frees all resources associate with this object.
42*/
43ClipboardHandler::~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*/
57void
58ClipboardHandler::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*/
196Clipboard*
197ClipboardHandler::_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