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