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
MethodReplicant(const char * signature)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
MethodReplicant(BMessage * message)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
~MethodReplicant()76 MethodReplicant::~MethodReplicant()
77 {
78 delete fSegments;
79 free(fSignature);
80 }
81
82
83 // archiving overrides
84 MethodReplicant*
Instantiate(BMessage * data)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
Archive(BMessage * data,bool deep) const95 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
AttachedToWindow()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
MessageReceived(BMessage * message)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
Draw(BRect rect)166 MethodReplicant::Draw(BRect rect)
167 {
168 BView::Draw(rect);
169
170 SetDrawingMode(B_OP_OVER);
171 DrawBitmap(fSegments);
172 }
173
174
175 void
MouseDown(BPoint point)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
MouseUp(BPoint point)199 MethodReplicant::MouseUp(BPoint point)
200 {
201 /* don't Quit() ! thanks for FFM users */
202 }
203
204
205 void
UpdateMethod(BMessage * message)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
UpdateMethodIcon(BMessage * message)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
UpdateMethodMenu(BMessage * message)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
UpdateMethodName(BMessage * message)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*
FindItemByCookie(int32 cookie)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
AddMethod(BMessage * message)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
RemoveMethod(BMessage * message)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