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