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 36MethodReplicant::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 55MethodReplicant::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 76MethodReplicant::~MethodReplicant() 77{ 78 delete fSegments; 79 free(fSignature); 80} 81 82 83// archiving overrides 84MethodReplicant* 85MethodReplicant::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 94status_t 95MethodReplicant::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 104void 105MethodReplicant::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 121void 122MethodReplicant::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 165void 166MethodReplicant::Draw(BRect rect) 167{ 168 BView::Draw(rect); 169 170 SetDrawingMode(B_OP_OVER); 171 DrawBitmap(fSegments); 172} 173 174 175void 176MethodReplicant::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 198void 199MethodReplicant::MouseUp(BPoint point) 200{ 201 /* don't Quit() ! thanks for FFM users */ 202} 203 204 205void 206MethodReplicant::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 228void 229MethodReplicant::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 256void 257MethodReplicant::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 306void 307MethodReplicant::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 332MethodMenuItem* 333MethodReplicant::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 346void 347MethodReplicant::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 407void 408MethodReplicant::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