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