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