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 (new BAlert("About Method Replicant", 141 "Method Replicant (Replicant)\n" 142 " Brought to you by Jérôme DUVAL.\n\n" 143 "Haiku, 2004-2009", "OK"))->Go(); 144 break; 145 case IS_UPDATE_NAME: 146 UpdateMethodName(message); 147 break; 148 case IS_UPDATE_ICON: 149 UpdateMethodIcon(message); 150 break; 151 case IS_UPDATE_MENU: 152 UpdateMethodMenu(message); 153 break; 154 case IS_UPDATE_METHOD: 155 UpdateMethod(message); 156 break; 157 case IS_ADD_METHOD: 158 AddMethod(message); 159 break; 160 case IS_REMOVE_METHOD: 161 RemoveMethod(message); 162 break; 163 164 default: 165 BView::MessageReceived(message); 166 break; 167 } 168 } 169 170 171 void 172 MethodReplicant::Draw(BRect rect) 173 { 174 BView::Draw(rect); 175 176 SetDrawingMode(B_OP_OVER); 177 DrawBitmap(fSegments); 178 } 179 180 181 void 182 MethodReplicant::MouseDown(BPoint point) 183 { 184 CALLED(); 185 uint32 mouseButtons; 186 BPoint where; 187 GetMouse(&where, &mouseButtons, true); 188 189 where = ConvertToScreen(point); 190 191 fMenu.SetTargetForItems(this); 192 BMenuItem* item = fMenu.Go(where, true, true, 193 BRect(where - BPoint(4, 4), where + BPoint(4, 4))); 194 195 if (dynamic_cast<MethodMenuItem*>(item) != NULL) { 196 BMessage msg(IS_SET_METHOD); 197 msg.AddInt32("cookie", ((MethodMenuItem*)item)->Cookie()); 198 BMessenger messenger(fSignature); 199 messenger.SendMessage(&msg); 200 } 201 } 202 203 204 void 205 MethodReplicant::MouseUp(BPoint point) 206 { 207 /* don't Quit() ! thanks for FFM users */ 208 } 209 210 211 void 212 MethodReplicant::UpdateMethod(BMessage* message) 213 { 214 CALLED(); 215 int32 cookie; 216 if (message->FindInt32("cookie", &cookie) != B_OK) { 217 fprintf(stderr, "can't find cookie in message\n"); 218 return; 219 } 220 221 MethodMenuItem* item = FindItemByCookie(cookie); 222 if (item == NULL) { 223 fprintf(stderr, "can't find item with cookie %lx\n", cookie); 224 return; 225 } 226 item->SetMarked(true); 227 228 fSegments->SetBits(item->Icon(), kRemoteWidth * kRemoteHeight, 0, 229 kRemoteColorSpace); 230 Invalidate(); 231 } 232 233 234 void 235 MethodReplicant::UpdateMethodIcon(BMessage* message) 236 { 237 CALLED(); 238 int32 cookie; 239 if (message->FindInt32("cookie", &cookie) != B_OK) { 240 fprintf(stderr, "can't find cookie in message\n"); 241 return; 242 } 243 244 const uchar* data; 245 ssize_t numBytes; 246 if (message->FindData("icon", B_ANY_TYPE, (const void**)&data, &numBytes) 247 != B_OK) { 248 fprintf(stderr, "can't find icon in message\n"); 249 return; 250 } 251 252 MethodMenuItem* item = FindItemByCookie(cookie); 253 if (item == NULL) { 254 fprintf(stderr, "can't find item with cookie 0x%lx\n", cookie); 255 return; 256 } 257 258 item->SetIcon(data); 259 } 260 261 262 void 263 MethodReplicant::UpdateMethodMenu(BMessage* message) 264 { 265 CALLED(); 266 int32 cookie; 267 if (message->FindInt32("cookie", &cookie) != B_OK) { 268 fprintf(stderr, "can't find cookie in message\n"); 269 return; 270 } 271 272 BMessage msg; 273 if (message->FindMessage("menu", &msg) != B_OK) { 274 fprintf(stderr, "can't find menu in message\n"); 275 return; 276 } 277 PRINT_OBJECT(msg); 278 279 BMessenger messenger; 280 if (message->FindMessenger("target", &messenger) != B_OK) { 281 fprintf(stderr, "can't find target in message\n"); 282 return; 283 } 284 285 BMenu* menu = (BMenu*)BMenu::Instantiate(&msg); 286 if (menu == NULL) { 287 PRINT(("can't instantiate menu\n")); 288 } else 289 menu->SetTargetForItems(messenger); 290 291 MethodMenuItem* item = FindItemByCookie(cookie); 292 if (item == NULL) { 293 fprintf(stderr, "can't find item with cookie 0x%lx\n", cookie); 294 return; 295 } 296 int32 index = fMenu.IndexOf(item); 297 298 MethodMenuItem* item2 = NULL; 299 if (menu) { 300 item2 = new MethodMenuItem(cookie, item->Label(), item->Icon(), 301 menu, messenger); 302 } else 303 item2 = new MethodMenuItem(cookie, item->Label(), item->Icon()); 304 305 item = (MethodMenuItem*)fMenu.RemoveItem(index); 306 fMenu.AddItem(item2, index); 307 item2->SetMarked(item->IsMarked()); 308 delete item; 309 } 310 311 312 void 313 MethodReplicant::UpdateMethodName(BMessage* message) 314 { 315 CALLED(); 316 int32 cookie; 317 if (message->FindInt32("cookie", &cookie) != B_OK) { 318 fprintf(stderr, "can't find cookie in message\n"); 319 return; 320 } 321 322 const char* name; 323 if (message->FindString("name", &name) != B_OK) { 324 fprintf(stderr, "can't find name in message\n"); 325 return; 326 } 327 328 MethodMenuItem* item = FindItemByCookie(cookie); 329 if (item == NULL) { 330 fprintf(stderr, "can't find item with cookie 0x%lx\n", cookie); 331 return; 332 } 333 334 item->SetName(name); 335 } 336 337 338 MethodMenuItem* 339 MethodReplicant::FindItemByCookie(int32 cookie) 340 { 341 for (int32 i = 0; i < fMenu.CountItems(); i++) { 342 MethodMenuItem* item = (MethodMenuItem*)fMenu.ItemAt(i); 343 PRINT(("cookie : 0x%lx\n", item->Cookie())); 344 if (item->Cookie() == cookie) 345 return item; 346 } 347 348 return NULL; 349 } 350 351 352 void 353 MethodReplicant::AddMethod(BMessage* message) 354 { 355 CALLED(); 356 int32 cookie; 357 if (message->FindInt32("cookie", &cookie) != B_OK) { 358 fprintf(stderr, "can't find cookie in message\n"); 359 return; 360 } 361 362 const char* name; 363 if (message->FindString("name", &name) != B_OK) { 364 fprintf(stderr, "can't find name in message\n"); 365 return; 366 } 367 368 const uchar* icon; 369 ssize_t numBytes; 370 if (message->FindData("icon", B_ANY_TYPE, (const void**)&icon, &numBytes) 371 != B_OK) { 372 fprintf(stderr, "can't find icon in message\n"); 373 return; 374 } 375 376 MethodMenuItem* item = FindItemByCookie(cookie); 377 if (item != NULL) { 378 fprintf(stderr, "item with cookie %lx already exists\n", cookie); 379 return; 380 } 381 382 item = new MethodMenuItem(cookie, name, icon); 383 fMenu.AddItem(item); 384 item->SetTarget(this); 385 386 if (fMenu.CountItems() == 1) 387 item->SetMarked(true); 388 } 389 390 391 void 392 MethodReplicant::RemoveMethod(BMessage* message) 393 { 394 CALLED(); 395 int32 cookie; 396 if (message->FindInt32("cookie", &cookie) != B_OK) { 397 fprintf(stderr, "can't find cookie in message\n"); 398 return; 399 } 400 401 MethodMenuItem* item = FindItemByCookie(cookie); 402 if (item == NULL) { 403 fprintf(stderr, "can't find item with cookie %lx\n", cookie); 404 return; 405 } 406 fMenu.RemoveItem(item); 407 delete item; 408 } 409