xref: /haiku/src/servers/input/MethodReplicant.cpp (revision 03187b607b2b5eec7ee059f1ead09bdba14991fb)
1 /*
2  * Copyright 2004-2009, Haiku. All rights reserved.
3  * Distributed under the terms of the MIT license.
4  *
5  * Authors:
6  *		Jérôme Duval
7  */
8 
9 
10 #include "MethodReplicant.h"
11 
12 #include <new>
13 #include <string.h>
14 
15 #include <Alert.h>
16 #include <AppDefs.h>
17 #include <Debug.h>
18 #include <Dragger.h>
19 #include <Bitmap.h>
20 #include <MenuItem.h>
21 #include <Message.h>
22 #include <Messenger.h>
23 #include <PopUpMenu.h>
24 
25 #include "remote_icon.h"
26 
27 #include "InputServerTypes.h"
28 
29 #ifdef DEBUG
30 #	define CALLED() PRINT(("CALLED %s \n", __PRETTY_FUNCTION__));
31 #else
32 #	define CALLED()
33 #endif
34 
35 
36 MethodReplicant::MethodReplicant(const char* signature)
37 	:
38 	BView(BRect(0, 0, 15, 15), REPLICANT_CTL_NAME, B_FOLLOW_ALL, B_WILL_DRAW),
39 	fMenu("", false, false)
40 {
41 	// Background Bitmap
42 	fSegments = new BBitmap(BRect(0, 0, kRemoteWidth - 1, kRemoteHeight - 1),
43 		kRemoteColorSpace);
44 	fSegments->SetBits(kRemoteBits, kRemoteWidth * kRemoteHeight, 0,
45 		kRemoteColorSpace);
46 	// Background Color
47 
48 	// add dragger
49 	BRect rect(Bounds());
50 	rect.left = rect.right - 7.0;
51 	rect.top = rect.bottom - 7.0;
52 	BDragger* dragger = new BDragger(rect, this,
53 		B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
54 	dragger->SetViewColor(B_TRANSPARENT_32_BIT);
55 	AddChild(dragger);
56 
57 	ASSERT(signature != NULL);
58 	fSignature = strdup(signature);
59 
60 	fMenu.SetFont(be_plain_font);
61 	fMenu.SetRadioMode(true);
62 }
63 
64 
65 MethodReplicant::MethodReplicant(BMessage* message)
66 	:
67 	BView(message),
68 	fMenu("", false, false)
69 {
70 	// Background Bitmap
71 	fSegments = new BBitmap(BRect(0, 0, kRemoteWidth - 1, kRemoteHeight - 1),
72 		kRemoteColorSpace);
73 	fSegments->SetBits(kRemoteBits, kRemoteWidth * kRemoteHeight, 0,
74 		kRemoteColorSpace);
75 
76 	const char* signature = NULL;
77 	message->FindString("add_on", &signature);
78 	ASSERT(signature != NULL);
79 	fSignature = strdup(signature);
80 
81 	fMenu.SetFont(be_plain_font);
82 	fMenu.SetRadioMode(true);
83 }
84 
85 
86 MethodReplicant::~MethodReplicant()
87 {
88 	delete fSegments;
89 	free(fSignature);
90 }
91 
92 
93 // archiving overrides
94 MethodReplicant*
95 MethodReplicant::Instantiate(BMessage* data)
96 {
97 	CALLED();
98 	if (!validate_instantiation(data, REPLICANT_CTL_NAME))
99 		return NULL;
100 	return new(std::nothrow) MethodReplicant(data);
101 }
102 
103 
104 status_t
105 MethodReplicant::Archive(BMessage* data, bool deep) const
106 {
107 	BView::Archive(data, deep);
108 
109 	data->AddString("add_on", fSignature);
110 	return B_NO_ERROR;
111 }
112 
113 
114 void
115 MethodReplicant::AttachedToWindow()
116 {
117 	CALLED();
118 
119 	SetViewColor(Parent()->ViewColor());
120 
121 	BMessenger messenger(this);
122 	BMessage msg(IS_METHOD_REGISTER);
123 	msg.AddMessenger("address", messenger);
124 
125 	BMessenger inputMessenger(fSignature);
126 	if (inputMessenger.SendMessage(&msg) != B_OK)
127 		printf("error when contacting input_server\n");
128 }
129 
130 
131 void
132 MethodReplicant::MessageReceived(BMessage* message)
133 {
134 	PRINT(("%s what:%c%c%c%c\n", __PRETTY_FUNCTION__, message->what >> 24,
135 		message->what >> 16, message->what >> 8, message->what));
136 	PRINT_OBJECT(*message);
137 
138 	switch (message->what) {
139 		case B_ABOUT_REQUESTED:
140 			(new BAlert("About Method Replicant",
141 				"Method Replicant (Replicant)\n"
142 				"  Brought to you by Jérôme DUVAL.\n\n"
143 				"Haiku, 2004-2009", "OK"))->Go();
144 			break;
145 		case IS_UPDATE_NAME:
146 			UpdateMethodName(message);
147 			break;
148 		case IS_UPDATE_ICON:
149 			UpdateMethodIcon(message);
150 			break;
151 		case IS_UPDATE_MENU:
152 			UpdateMethodMenu(message);
153 			break;
154 		case IS_UPDATE_METHOD:
155 			UpdateMethod(message);
156 			break;
157 		case IS_ADD_METHOD:
158 			AddMethod(message);
159 			break;
160 		case IS_REMOVE_METHOD:
161 			RemoveMethod(message);
162 			break;
163 
164 		default:
165 			BView::MessageReceived(message);
166 			break;
167 	}
168 }
169 
170 
171 void
172 MethodReplicant::Draw(BRect rect)
173 {
174 	BView::Draw(rect);
175 
176 	SetDrawingMode(B_OP_OVER);
177 	DrawBitmap(fSegments);
178 }
179 
180 
181 void
182 MethodReplicant::MouseDown(BPoint point)
183 {
184 	CALLED();
185 	uint32 mouseButtons;
186 	BPoint where;
187 	GetMouse(&where, &mouseButtons, true);
188 
189 	where = ConvertToScreen(point);
190 
191 	fMenu.SetTargetForItems(this);
192 	BMenuItem* item = fMenu.Go(where, true, true,
193 		BRect(where - BPoint(4, 4), where + BPoint(4, 4)));
194 
195 	if (dynamic_cast<MethodMenuItem*>(item) != NULL) {
196 		BMessage msg(IS_SET_METHOD);
197 		msg.AddInt32("cookie", ((MethodMenuItem*)item)->Cookie());
198 		BMessenger messenger(fSignature);
199 		messenger.SendMessage(&msg);
200 	}
201 }
202 
203 
204 void
205 MethodReplicant::MouseUp(BPoint point)
206 {
207 	/* don't Quit() ! thanks for FFM users */
208 }
209 
210 
211 void
212 MethodReplicant::UpdateMethod(BMessage* message)
213 {
214 	CALLED();
215 	int32 cookie;
216 	if (message->FindInt32("cookie", &cookie) != B_OK) {
217 		fprintf(stderr, "can't find cookie in message\n");
218 		return;
219 	}
220 
221 	MethodMenuItem* item = FindItemByCookie(cookie);
222 	if (item == NULL) {
223 		fprintf(stderr, "can't find item with cookie %lx\n", cookie);
224 		return;
225 	}
226 	item->SetMarked(true);
227 
228 	fSegments->SetBits(item->Icon(), kRemoteWidth * kRemoteHeight, 0,
229 		kRemoteColorSpace);
230 	Invalidate();
231 }
232 
233 
234 void
235 MethodReplicant::UpdateMethodIcon(BMessage* message)
236 {
237 	CALLED();
238 	int32 cookie;
239 	if (message->FindInt32("cookie", &cookie) != B_OK) {
240 		fprintf(stderr, "can't find cookie in message\n");
241 		return;
242 	}
243 
244 	const uchar* data;
245 	ssize_t numBytes;
246 	if (message->FindData("icon", B_ANY_TYPE, (const void**)&data, &numBytes)
247 			!= B_OK) {
248 		fprintf(stderr, "can't find icon in message\n");
249 		return;
250 	}
251 
252 	MethodMenuItem* item = FindItemByCookie(cookie);
253 	if (item == NULL) {
254 		fprintf(stderr, "can't find item with cookie 0x%lx\n", cookie);
255 		return;
256 	}
257 
258 	item->SetIcon(data);
259 }
260 
261 
262 void
263 MethodReplicant::UpdateMethodMenu(BMessage* message)
264 {
265 	CALLED();
266 	int32 cookie;
267 	if (message->FindInt32("cookie", &cookie) != B_OK) {
268 		fprintf(stderr, "can't find cookie in message\n");
269 		return;
270 	}
271 
272 	BMessage msg;
273 	if (message->FindMessage("menu", &msg) != B_OK) {
274 		fprintf(stderr, "can't find menu in message\n");
275 		return;
276 	}
277 	PRINT_OBJECT(msg);
278 
279 	BMessenger messenger;
280 	if (message->FindMessenger("target", &messenger) != B_OK) {
281 		fprintf(stderr, "can't find target in message\n");
282 		return;
283 	}
284 
285 	BMenu* menu = (BMenu*)BMenu::Instantiate(&msg);
286 	if (menu == NULL) {
287 		PRINT(("can't instantiate menu\n"));
288 	} else
289 		menu->SetTargetForItems(messenger);
290 
291 	MethodMenuItem* item = FindItemByCookie(cookie);
292 	if (item == NULL) {
293 		fprintf(stderr, "can't find item with cookie 0x%lx\n", cookie);
294 		return;
295 	}
296 	int32 index = fMenu.IndexOf(item);
297 
298 	MethodMenuItem* item2 = NULL;
299 	if (menu) {
300 		item2 = new MethodMenuItem(cookie, item->Label(), item->Icon(),
301 			menu, messenger);
302 	} else
303 		item2 = new MethodMenuItem(cookie, item->Label(), item->Icon());
304 
305 	item = (MethodMenuItem*)fMenu.RemoveItem(index);
306 	fMenu.AddItem(item2, index);
307 	item2->SetMarked(item->IsMarked());
308 	delete item;
309 }
310 
311 
312 void
313 MethodReplicant::UpdateMethodName(BMessage* message)
314 {
315 	CALLED();
316 	int32 cookie;
317 	if (message->FindInt32("cookie", &cookie) != B_OK) {
318 		fprintf(stderr, "can't find cookie in message\n");
319 		return;
320 	}
321 
322 	const char* name;
323 	if (message->FindString("name", &name) != B_OK) {
324 		fprintf(stderr, "can't find name in message\n");
325 		return;
326 	}
327 
328 	MethodMenuItem* item = FindItemByCookie(cookie);
329 	if (item == NULL) {
330 		fprintf(stderr, "can't find item with cookie 0x%lx\n", cookie);
331 		return;
332 	}
333 
334 	item->SetName(name);
335 }
336 
337 
338 MethodMenuItem*
339 MethodReplicant::FindItemByCookie(int32 cookie)
340 {
341 	for (int32 i = 0; i < fMenu.CountItems(); i++) {
342 		MethodMenuItem* item = (MethodMenuItem*)fMenu.ItemAt(i);
343 		PRINT(("cookie : 0x%lx\n", item->Cookie()));
344 		if (item->Cookie() == cookie)
345 			return item;
346 	}
347 
348 	return NULL;
349 }
350 
351 
352 void
353 MethodReplicant::AddMethod(BMessage* message)
354 {
355 	CALLED();
356 	int32 cookie;
357 	if (message->FindInt32("cookie", &cookie) != B_OK) {
358 		fprintf(stderr, "can't find cookie in message\n");
359 		return;
360 	}
361 
362 	const char* name;
363 	if (message->FindString("name", &name) != B_OK) {
364 		fprintf(stderr, "can't find name in message\n");
365 		return;
366 	}
367 
368 	const uchar* icon;
369 	ssize_t numBytes;
370 	if (message->FindData("icon", B_ANY_TYPE, (const void**)&icon, &numBytes)
371 			!= B_OK) {
372 		fprintf(stderr, "can't find icon in message\n");
373 		return;
374 	}
375 
376 	MethodMenuItem* item = FindItemByCookie(cookie);
377 	if (item != NULL) {
378 		fprintf(stderr, "item with cookie %lx already exists\n", cookie);
379 		return;
380 	}
381 
382 	item = new MethodMenuItem(cookie, name, icon);
383 	fMenu.AddItem(item);
384 	item->SetTarget(this);
385 
386 	if (fMenu.CountItems() == 1)
387 		item->SetMarked(true);
388 }
389 
390 
391 void
392 MethodReplicant::RemoveMethod(BMessage* message)
393 {
394 	CALLED();
395 	int32 cookie;
396 	if (message->FindInt32("cookie", &cookie) != B_OK) {
397 		fprintf(stderr, "can't find cookie in message\n");
398 		return;
399 	}
400 
401 	MethodMenuItem* item = FindItemByCookie(cookie);
402 	if (item == NULL) {
403 		fprintf(stderr, "can't find item with cookie %lx\n", cookie);
404 		return;
405 	}
406 	fMenu.RemoveItem(item);
407 	delete item;
408 }
409