xref: /haiku/src/servers/input/MethodReplicant.cpp (revision 579f1dbca962a2a03df54f69fdc6e9423f91f20e)
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 		{
141 			BAlert* alert = new BAlert("About Method Replicant",
142 				"Method Replicant (Replicant)\n"
143 				"  Brought to you by Jérôme DUVAL.\n\n"
144 				"Haiku, 2004-2009", "OK");
145 			alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
146 			alert->Go();
147 			break;
148 		}
149 		case IS_UPDATE_NAME:
150 			UpdateMethodName(message);
151 			break;
152 		case IS_UPDATE_ICON:
153 			UpdateMethodIcon(message);
154 			break;
155 		case IS_UPDATE_MENU:
156 			UpdateMethodMenu(message);
157 			break;
158 		case IS_UPDATE_METHOD:
159 			UpdateMethod(message);
160 			break;
161 		case IS_ADD_METHOD:
162 			AddMethod(message);
163 			break;
164 		case IS_REMOVE_METHOD:
165 			RemoveMethod(message);
166 			break;
167 
168 		default:
169 			BView::MessageReceived(message);
170 			break;
171 	}
172 }
173 
174 
175 void
176 MethodReplicant::Draw(BRect rect)
177 {
178 	BView::Draw(rect);
179 
180 	SetDrawingMode(B_OP_OVER);
181 	DrawBitmap(fSegments);
182 }
183 
184 
185 void
186 MethodReplicant::MouseDown(BPoint point)
187 {
188 	CALLED();
189 	uint32 mouseButtons;
190 	BPoint where;
191 	GetMouse(&where, &mouseButtons, true);
192 
193 	where = ConvertToScreen(point);
194 
195 	fMenu.SetTargetForItems(this);
196 	BMenuItem* item = fMenu.Go(where, true, true,
197 		BRect(where - BPoint(4, 4), where + BPoint(4, 4)));
198 
199 	if (dynamic_cast<MethodMenuItem*>(item) != NULL) {
200 		BMessage msg(IS_SET_METHOD);
201 		msg.AddPointer("cookie", ((MethodMenuItem*)item)->Cookie());
202 		BMessenger messenger(fSignature);
203 		messenger.SendMessage(&msg);
204 	}
205 }
206 
207 
208 void
209 MethodReplicant::MouseUp(BPoint point)
210 {
211 	/* don't Quit() ! thanks for FFM users */
212 }
213 
214 
215 void
216 MethodReplicant::UpdateMethod(BMessage* message)
217 {
218 	CALLED();
219 	void* cookie;
220 	if (message->FindPointer("cookie", &cookie) != B_OK) {
221 		fprintf(stderr, "can't find cookie in message\n");
222 		return;
223 	}
224 
225 	MethodMenuItem* item = FindItemByCookie(cookie);
226 	if (item == NULL) {
227 		fprintf(stderr, "can't find item with cookie %p\n", cookie);
228 		return;
229 	}
230 	item->SetMarked(true);
231 
232 	fSegments->SetBits(item->Icon(), kRemoteWidth * kRemoteHeight, 0,
233 		kRemoteColorSpace);
234 	Invalidate();
235 }
236 
237 
238 void
239 MethodReplicant::UpdateMethodIcon(BMessage* message)
240 {
241 	CALLED();
242 	void* cookie;
243 	if (message->FindPointer("cookie", &cookie) != B_OK) {
244 		fprintf(stderr, "can't find cookie in message\n");
245 		return;
246 	}
247 
248 	const uchar* data;
249 	ssize_t numBytes;
250 	if (message->FindData("icon", B_ANY_TYPE, (const void**)&data, &numBytes)
251 			!= B_OK) {
252 		fprintf(stderr, "can't find icon in message\n");
253 		return;
254 	}
255 
256 	MethodMenuItem* item = FindItemByCookie(cookie);
257 	if (item == NULL) {
258 		fprintf(stderr, "can't find item with cookie %p\n", cookie);
259 		return;
260 	}
261 
262 	item->SetIcon(data);
263 }
264 
265 
266 void
267 MethodReplicant::UpdateMethodMenu(BMessage* message)
268 {
269 	CALLED();
270 	void* cookie;
271 	if (message->FindPointer("cookie", &cookie) != B_OK) {
272 		fprintf(stderr, "can't find cookie in message\n");
273 		return;
274 	}
275 
276 	BMessage msg;
277 	if (message->FindMessage("menu", &msg) != B_OK) {
278 		fprintf(stderr, "can't find menu in message\n");
279 		return;
280 	}
281 	PRINT_OBJECT(msg);
282 
283 	BMessenger messenger;
284 	if (message->FindMessenger("target", &messenger) != B_OK) {
285 		fprintf(stderr, "can't find target in message\n");
286 		return;
287 	}
288 
289 	BMenu* menu = (BMenu*)BMenu::Instantiate(&msg);
290 	if (menu == NULL) {
291 		PRINT(("can't instantiate menu\n"));
292 	} else
293 		menu->SetTargetForItems(messenger);
294 
295 	MethodMenuItem* item = FindItemByCookie(cookie);
296 	if (item == NULL) {
297 		fprintf(stderr, "can't find item with cookie %p\n", cookie);
298 		return;
299 	}
300 	int32 index = fMenu.IndexOf(item);
301 
302 	MethodMenuItem* item2 = NULL;
303 	if (menu) {
304 		item2 = new MethodMenuItem(cookie, item->Label(), item->Icon(),
305 			menu, messenger);
306 	} else
307 		item2 = new MethodMenuItem(cookie, item->Label(), item->Icon());
308 
309 	item = (MethodMenuItem*)fMenu.RemoveItem(index);
310 	fMenu.AddItem(item2, index);
311 	item2->SetMarked(item->IsMarked());
312 	delete item;
313 }
314 
315 
316 void
317 MethodReplicant::UpdateMethodName(BMessage* message)
318 {
319 	CALLED();
320 	void* cookie;
321 	if (message->FindPointer("cookie", &cookie) != B_OK) {
322 		fprintf(stderr, "can't find cookie in message\n");
323 		return;
324 	}
325 
326 	const char* name;
327 	if (message->FindString("name", &name) != B_OK) {
328 		fprintf(stderr, "can't find name in message\n");
329 		return;
330 	}
331 
332 	MethodMenuItem* item = FindItemByCookie(cookie);
333 	if (item == NULL) {
334 		fprintf(stderr, "can't find item with cookie %p\n", cookie);
335 		return;
336 	}
337 
338 	item->SetName(name);
339 }
340 
341 
342 MethodMenuItem*
343 MethodReplicant::FindItemByCookie(void* cookie)
344 {
345 	for (int32 i = 0; i < fMenu.CountItems(); i++) {
346 		MethodMenuItem* item = (MethodMenuItem*)fMenu.ItemAt(i);
347 		PRINT(("cookie : %p\n", item->Cookie()));
348 		if (item->Cookie() == cookie)
349 			return item;
350 	}
351 
352 	return NULL;
353 }
354 
355 
356 void
357 MethodReplicant::AddMethod(BMessage* message)
358 {
359 	CALLED();
360 	void* cookie;
361 	if (message->FindPointer("cookie", &cookie) != B_OK) {
362 		fprintf(stderr, "can't find cookie in message\n");
363 		return;
364 	}
365 
366 	const char* name;
367 	if (message->FindString("name", &name) != B_OK) {
368 		fprintf(stderr, "can't find name in message\n");
369 		return;
370 	}
371 
372 	const uchar* icon;
373 	ssize_t numBytes;
374 	if (message->FindData("icon", B_ANY_TYPE, (const void**)&icon, &numBytes)
375 			!= B_OK) {
376 		fprintf(stderr, "can't find icon in message\n");
377 		return;
378 	}
379 
380 	MethodMenuItem* item = FindItemByCookie(cookie);
381 	if (item != NULL) {
382 		fprintf(stderr, "item with cookie %p already exists\n", cookie);
383 		return;
384 	}
385 
386 	item = new MethodMenuItem(cookie, name, icon);
387 	fMenu.AddItem(item);
388 	item->SetTarget(this);
389 
390 	if (fMenu.CountItems() == 1)
391 		item->SetMarked(true);
392 }
393 
394 
395 void
396 MethodReplicant::RemoveMethod(BMessage* message)
397 {
398 	CALLED();
399 	void* cookie;
400 	if (message->FindPointer("cookie", &cookie) != B_OK) {
401 		fprintf(stderr, "can't find cookie in message\n");
402 		return;
403 	}
404 
405 	MethodMenuItem* item = FindItemByCookie(cookie);
406 	if (item == NULL) {
407 		fprintf(stderr, "can't find item with cookie %p\n", cookie);
408 		return;
409 	}
410 	fMenu.RemoveItem(item);
411 	delete item;
412 }
413