1 /* 2 * Copyright 2010-2017, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Pier Luigi Fiorini, pierluigi.fiorini@gmail.com 7 * Stephan Aßmus, superstippi@gmx.de 8 * Brian Hill, supernova@tycho.email 9 */ 10 11 12 #include <Notification.h> 13 14 #include <new> 15 16 #include <stdlib.h> 17 #include <string.h> 18 19 #include <notification/Notifications.h> 20 21 #include <Bitmap.h> 22 #include <Message.h> 23 #include <NodeInfo.h> 24 #include <Path.h> 25 #include <Roster.h> 26 27 28 BNotification::BNotification(notification_type type) 29 : 30 BArchivable(), 31 fInitStatus(B_OK), 32 fType(type), 33 fProgress(0.f), 34 fFile(NULL), 35 fBitmap(NULL) 36 { 37 team_info teamInfo; 38 get_team_info(B_CURRENT_TEAM, &teamInfo); 39 app_info appInfo; 40 be_roster->GetRunningAppInfo(teamInfo.team, &appInfo); 41 42 int32 iconSize = B_LARGE_ICON; 43 fBitmap = new BBitmap(BRect(0, 0, iconSize - 1, iconSize - 1), 0, B_RGBA32); 44 if (fBitmap) { 45 if (BNodeInfo::GetTrackerIcon(&appInfo.ref, fBitmap, 46 icon_size(iconSize)) != B_OK) { 47 delete fBitmap; 48 fBitmap = NULL; 49 } 50 } 51 fSourceSignature = appInfo.signature; 52 BPath path(&appInfo.ref); 53 if (path.InitCheck() == B_OK) 54 fSourceName = path.Leaf(); 55 } 56 57 58 BNotification::BNotification(BMessage* archive) 59 : 60 BArchivable(archive), 61 fInitStatus(B_OK), 62 fProgress(0.0f), 63 fFile(NULL), 64 fBitmap(NULL) 65 { 66 BString appName; 67 if (archive->FindString("_appname", &appName) == B_OK) 68 fSourceName = appName; 69 70 BString signature; 71 if (archive->FindString("_signature", &signature) == B_OK) 72 fSourceSignature = signature; 73 74 int32 type; 75 if (archive->FindInt32("_type", &type) == B_OK) 76 fType = (notification_type)type; 77 else 78 fInitStatus = B_ERROR; 79 80 BString group; 81 if (archive->FindString("_group", &group) == B_OK) 82 SetGroup(group); 83 84 BString title; 85 if (archive->FindString("_title", &title) == B_OK) 86 SetTitle(title); 87 88 BString content; 89 if (archive->FindString("_content", &content) == B_OK) 90 SetContent(content); 91 92 BString messageID; 93 if (archive->FindString("_messageID", &messageID) == B_OK) 94 SetMessageID(messageID); 95 96 float progress; 97 if (type == B_PROGRESS_NOTIFICATION 98 && archive->FindFloat("_progress", &progress) == B_OK) 99 SetProgress(progress); 100 101 BString onClickApp; 102 if (archive->FindString("_onClickApp", &onClickApp) == B_OK) 103 SetOnClickApp(onClickApp); 104 105 entry_ref onClickFile; 106 if (archive->FindRef("_onClickFile", &onClickFile) == B_OK) 107 SetOnClickFile(&onClickFile); 108 109 entry_ref onClickRef; 110 int32 index = 0; 111 while (archive->FindRef("_onClickRef", index++, &onClickRef) == B_OK) 112 AddOnClickRef(&onClickRef); 113 114 BString onClickArgv; 115 index = 0; 116 while (archive->FindString("_onClickArgv", index++, &onClickArgv) == B_OK) 117 AddOnClickArg(onClickArgv); 118 119 status_t ret = B_OK; 120 BMessage icon; 121 if ((ret = archive->FindMessage("_icon", &icon)) == B_OK) { 122 BBitmap bitmap(&icon); 123 ret = bitmap.InitCheck(); 124 if (ret == B_OK) 125 ret = SetIcon(&bitmap); 126 } 127 } 128 129 130 BNotification::~BNotification() 131 { 132 delete fFile; 133 delete fBitmap; 134 135 for (int32 i = fRefs.CountItems() - 1; i >= 0; i--) 136 delete (entry_ref*)fRefs.ItemAtFast(i); 137 138 for (int32 i = fArgv.CountItems() - 1; i >= 0; i--) 139 free(fArgv.ItemAtFast(i)); 140 } 141 142 143 /*! \brief Returns initialization status. 144 */ 145 status_t 146 BNotification::InitCheck() const 147 { 148 return fInitStatus; 149 } 150 151 152 /*! \brief Returns a new BNotification object from @archive. 153 154 Returns a new BNotification object, allocated by new and created 155 with the version of the constructor that takes BMessage archive. 156 However, if the message doesn't contain an archived data for a 157 BNotification object, this method returns NULL. 158 159 \return BNotification object from @archive or NULL if it doesn't 160 contain a valid BNotification object. 161 */ 162 BArchivable* 163 BNotification::Instantiate(BMessage* archive) 164 { 165 if (validate_instantiation(archive, "BNotification")) 166 return new(std::nothrow) BNotification(archive); 167 168 return NULL; 169 } 170 171 172 /*! \brief Archives the BNotification in the BMessages @archive. 173 174 \sa BArchivable::Archive(), Instantiate() static function. 175 \return 176 - \c B_OK: Everything went fine. 177 - \c Other errors: Archiving has failed. 178 */ 179 status_t 180 BNotification::Archive(BMessage* archive, bool deep) const 181 { 182 status_t status = BArchivable::Archive(archive, deep); 183 184 if (status == B_OK) 185 status = archive->AddString("_appname", fSourceName); 186 187 if (status == B_OK) 188 status = archive->AddString("_signature", fSourceSignature); 189 190 if (status == B_OK) 191 status = archive->AddInt32("_type", (int32)fType); 192 193 if (status == B_OK && Group() != NULL) 194 status = archive->AddString("_group", Group()); 195 196 if (status == B_OK && Title() != NULL) 197 status = archive->AddString("_title", Title()); 198 199 if (status == B_OK && Content() != NULL) 200 status = archive->AddString("_content", Content()); 201 202 if (status == B_OK && MessageID() != NULL) 203 status = archive->AddString("_messageID", MessageID()); 204 205 if (status == B_OK && Type() == B_PROGRESS_NOTIFICATION) 206 status = archive->AddFloat("_progress", Progress()); 207 208 if (status == B_OK && OnClickApp() != NULL) 209 status = archive->AddString("_onClickApp", OnClickApp()); 210 211 if (status == B_OK && OnClickFile() != NULL) 212 status = archive->AddRef("_onClickFile", OnClickFile()); 213 214 if (status == B_OK) { 215 for (int32 i = 0; i < CountOnClickRefs(); i++) { 216 status = archive->AddRef("_onClickRef", OnClickRefAt(i)); 217 if (status != B_OK) 218 break; 219 } 220 } 221 222 if (status == B_OK) { 223 for (int32 i = 0; i < CountOnClickArgs(); i++) { 224 status = archive->AddString("_onClickArgv", OnClickArgAt(i)); 225 if (status != B_OK) 226 break; 227 } 228 } 229 230 if (status == B_OK) { 231 const BBitmap* icon = Icon(); 232 if (icon != NULL) { 233 BMessage iconArchive; 234 status = icon->Archive(&iconArchive); 235 if (status == B_OK) 236 archive->AddMessage("_icon", &iconArchive); 237 } 238 } 239 240 return status; 241 } 242 243 244 /*! \brief Returns source application signature. 245 246 \return Source application signature. 247 */ 248 const char* 249 BNotification::SourceSignature() const 250 { 251 return fSourceSignature; 252 } 253 254 255 /*! \brief Returns source application name. 256 257 \return Source application name. 258 */ 259 const char* 260 BNotification::SourceName() const 261 { 262 return fSourceName; 263 } 264 265 266 /*! \brief Notification's type. 267 268 \return A value of the notification_type enum that represents 269 notification type. 270 */ 271 notification_type 272 BNotification::Type() const 273 { 274 return fType; 275 } 276 277 278 /*! \brief Returns notification's group. 279 280 \return Notification's group. 281 */ 282 const char* 283 BNotification::Group() const 284 { 285 if (fGroup == "") 286 return NULL; 287 return fGroup; 288 } 289 290 291 /*! \brief Sets notification's group. 292 293 Notifications can be grouped together setting the same group. 294 */ 295 void 296 BNotification::SetGroup(const BString& group) 297 { 298 fGroup = group; 299 } 300 301 302 /*! \brief Returns notification's title. 303 304 \return Notification's title. 305 */ 306 const char* 307 BNotification::Title() const 308 { 309 if (fTitle == "") 310 return NULL; 311 return fTitle; 312 } 313 314 315 /*! \brief Set notification's title. 316 */ 317 void 318 BNotification::SetTitle(const BString& title) 319 { 320 fTitle = title; 321 } 322 323 324 /*! \brief Returns notification's message. 325 326 \return Notification's message. 327 */ 328 const char* 329 BNotification::Content() const 330 { 331 if (fContent == "") 332 return NULL; 333 return fContent; 334 } 335 336 337 /*! \brief Sets notification's message. 338 */ 339 void 340 BNotification::SetContent(const BString& content) 341 { 342 fContent = content; 343 } 344 345 346 /*! \brief Returns notification's message identifier. 347 348 \return Notification's message identifier. 349 */ 350 const char* 351 BNotification::MessageID() const 352 { 353 if (fID == "") 354 return NULL; 355 return fID; 356 } 357 358 359 /*! \brief Sets notification's message identifier. 360 */ 361 void 362 BNotification::SetMessageID(const BString& id) 363 { 364 fID = id; 365 } 366 367 368 /*! \brief Returns progress information. 369 370 If notification's type is \c B_PROGRESS_NOTIFICATION, returns a value 371 between 0.0 and 1.0 that represent progress percentage. 372 373 If notification's type is not \c B_PROGRESS_NOTIFICATION, returns -1. 374 375 \return Percentage if notification's type is B_PROGRESS_NOTIFICATION 376 or otherwise -1. 377 */ 378 float 379 BNotification::Progress() const 380 { 381 if (fType != B_PROGRESS_NOTIFICATION) 382 return -1; 383 return fProgress; 384 } 385 386 387 /*! \brief Sets progress information. 388 389 Sets progress percentage, this information will be used only 390 if notification's type is \c B_PROGRESS_NOTIFICATION. 391 392 The value of @progress must be between 0.0 and 1.0. 393 */ 394 void 395 BNotification::SetProgress(float progress) 396 { 397 if (progress < 0) 398 fProgress = 0; 399 else if (progress > 1) 400 fProgress = 1; 401 else 402 fProgress = progress; 403 } 404 405 406 const char* 407 BNotification::OnClickApp() const 408 { 409 if (fApp == "") 410 return NULL; 411 return fApp; 412 } 413 414 415 void 416 BNotification::SetOnClickApp(const BString& app) 417 { 418 fApp = app; 419 } 420 421 422 const entry_ref* 423 BNotification::OnClickFile() const 424 { 425 return fFile; 426 } 427 428 429 status_t 430 BNotification::SetOnClickFile(const entry_ref* file) 431 { 432 delete fFile; 433 434 if (file != NULL) { 435 fFile = new(std::nothrow) entry_ref(*file); 436 if (fFile == NULL) 437 return B_NO_MEMORY; 438 } else 439 fFile = NULL; 440 441 return B_OK; 442 } 443 444 445 status_t 446 BNotification::AddOnClickRef(const entry_ref* ref) 447 { 448 if (ref == NULL) 449 return B_BAD_VALUE; 450 451 entry_ref* clonedRef = new(std::nothrow) entry_ref(*ref); 452 if (clonedRef == NULL || !fRefs.AddItem(clonedRef)) 453 return B_NO_MEMORY; 454 455 return B_OK; 456 } 457 458 459 int32 460 BNotification::CountOnClickRefs() const 461 { 462 return fRefs.CountItems(); 463 } 464 465 466 const entry_ref* 467 BNotification::OnClickRefAt(int32 index) const 468 { 469 return (entry_ref*)fArgv.ItemAt(index); 470 } 471 472 473 status_t 474 BNotification::AddOnClickArg(const BString& arg) 475 { 476 char* clonedArg = strdup(arg.String()); 477 if (clonedArg == NULL || !fArgv.AddItem(clonedArg)) 478 return B_NO_MEMORY; 479 480 return B_OK; 481 } 482 483 484 int32 485 BNotification::CountOnClickArgs() const 486 { 487 return fArgv.CountItems(); 488 } 489 490 491 const char* 492 BNotification::OnClickArgAt(int32 index) const 493 { 494 return (char*)fArgv.ItemAt(index); 495 } 496 497 498 /*! \brief Notification's icon. 499 500 \return Notification's icon. 501 */ 502 const BBitmap* 503 BNotification::Icon() const 504 { 505 return fBitmap; 506 } 507 508 509 /*! \brief Sets notification's icon. 510 511 Sets notification's icon. 512 This method does not assume ownership of @icon. 513 514 \param icon Icon 515 \return 516 - \c B_OK: Everything went fine. 517 - \c B_NO_MEMORY: Allocation of @icon copy has failed. 518 - \c Other errors: Creation of @icon copy failed for some reason. 519 */ 520 status_t 521 BNotification::SetIcon(const BBitmap* icon) 522 { 523 delete fBitmap; 524 525 if (icon != NULL) { 526 fBitmap = new(std::nothrow) BBitmap(icon); 527 if (fBitmap == NULL) 528 return B_NO_MEMORY; 529 return fBitmap->InitCheck(); 530 } 531 532 fBitmap = NULL; 533 return B_OK; 534 } 535 536 537 /*! \brief Sends a notification to the notification_server. 538 539 The notification is delivered asynchronously to the notification_server, 540 which will display it according to its settings and filters. 541 542 \param timeout Microseconds after the message fades out. 543 \return 544 - \c B_OK: Everything went fine. 545 - \c B_BAD_PORT_ID: A connection to notification_server could not be 546 established or the server is not up and running anymore. 547 - \c Other errors: Building the message from the notification failed. 548 */ 549 status_t 550 BNotification::Send(bigtime_t timeout) 551 { 552 BMessage msg(kNotificationMessage); 553 554 // Archive notification 555 status_t ret = Archive(&msg); 556 557 // Custom time out 558 if (ret == B_OK && timeout > 0) 559 ret = msg.AddInt64("timeout", timeout); 560 561 // Send message 562 if (ret == B_OK) { 563 BMessenger server(kNotificationServerSignature); 564 ret = server.SendMessage(&msg); 565 } 566 567 return ret; 568 } 569 570 571 void BNotification::_ReservedNotification1() {} 572 void BNotification::_ReservedNotification2() {} 573 void BNotification::_ReservedNotification3() {} 574 void BNotification::_ReservedNotification4() {} 575 void BNotification::_ReservedNotification5() {} 576 void BNotification::_ReservedNotification6() {} 577 void BNotification::_ReservedNotification7() {} 578 void BNotification::_ReservedNotification8() {} 579