xref: /haiku/src/kits/app/Notification.cpp (revision 3995592cdf304335132305e27c40cbb0b1ac46e3)
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