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