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