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