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