Merge patch by plfiorini :

Some changes to the API for notifications.
	* Don't go through be_roster to send a notification, but use Notification->Send() instead.
	* Rename App to Group to make the purpose clearer

And some changes to the notification code itself:
	* Use the Notification class as the way to convey informations about a notification. Allows easier extension of this class
	* Code cleanup
	* Use of the layout kit for the notify window

Unfortunately, the latter part clashes quite a bit with the changes I already did to the notification window, so it's now quite broken. Working on that next, but I wanted to separate that work from the patch ...


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@43114 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Adrien Destugues 2011-11-02 14:57:43 +00:00
parent 561696cbfc
commit 4ec6c3a042
19 changed files with 321 additions and 785 deletions

View File

@ -6,6 +6,7 @@
#define _NOTIFICATION_H #define _NOTIFICATION_H
#include <Archivable.h>
#include <Entry.h> #include <Entry.h>
#include <List.h> #include <List.h>
#include <String.h> #include <String.h>
@ -22,15 +23,21 @@ enum notification_type {
class BBitmap; class BBitmap;
class BNotification { class BNotification : public BArchivable {
public: public:
BNotification(notification_type type); BNotification(notification_type type);
~BNotification(); BNotification(BMessage* archive);
virtual ~BNotification();
status_t InitCheck() const;
static BArchivable* Instantiate(BMessage* archive);
virtual status_t Archive(BMessage* archive, bool deep = true) const;
notification_type Type() const; notification_type Type() const;
const char* Application() const; const char* Group() const;
void SetApplication(const BString& app); void SetGroup(const BString& group);
const char* Title() const; const char* Title() const;
void SetTitle(const BString& title); void SetTitle(const BString& title);
@ -61,9 +68,13 @@ public:
const BBitmap* Icon() const; const BBitmap* Icon() const;
status_t SetIcon(const BBitmap* icon); status_t SetIcon(const BBitmap* icon);
status_t Send(bigtime_t timeout = -1);
private: private:
status_t fInitStatus;
notification_type fType; notification_type fType;
BString fAppName; BString fGroup;
BString fTitle; BString fTitle;
BString fContent; BString fContent;
BString fID; BString fID;

View File

@ -13,7 +13,6 @@
class BFile; class BFile;
class BMimeType; class BMimeType;
class BNodeInfo; class BNodeInfo;
class BNotification;
struct app_info { struct app_info {
@ -117,10 +116,6 @@ class BRoster {
void AddToRecentFolders(const entry_ref *folder, void AddToRecentFolders(const entry_ref *folder,
const char *appSig = 0) const; const char *appSig = 0) const;
// notifications
status_t Notify(const BNotification& notification,
bigtime_t timeout = -1) const;
// private/reserved stuff starts here // private/reserved stuff starts here
class Private; class Private;

View File

@ -28,15 +28,6 @@ typedef enum {
} b_mail_status_window_option; } b_mail_status_window_option;
typedef enum {
B_MAIL_STATUS_LOOK_TITLED = 0,
B_MAIL_STATUS_LOOK_NORMAL_BORDER = 1,
B_MAIL_STATUS_LOOK_FLOATING = 2,
B_MAIL_STATUS_LOOK_THIN_BORDER = 3,
B_MAIL_STATUS_LOOK_NO_BORDER = 4
} b_mail_status_window_look;
class BMailSettings { class BMailSettings {
public: public:
BMailSettings(); BMailSettings();

View File

@ -10,7 +10,6 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <Application.h> #include <Application.h>
#include <Bitmap.h> #include <Bitmap.h>
@ -19,7 +18,6 @@
#include <Mime.h> #include <Mime.h>
#include <Notification.h> #include <Notification.h>
#include <Path.h> #include <Path.h>
#include <Roster.h>
#include <TranslationUtils.h> #include <TranslationUtils.h>
const char* kSignature = "application/x-vnd.Haiku-notify"; const char* kSignature = "application/x-vnd.Haiku-notify";
@ -52,15 +50,15 @@ public:
private: private:
bool fHasGoodArguments; bool fHasGoodArguments;
notification_type fType; notification_type fType;
char* fAppName; BString fGroup;
char* fTitle; BString fTitle;
char* fMsgId; BString fMsgId;
float fProgress; float fProgress;
bigtime_t fTimeout; bigtime_t fTimeout;
char* fIconFile; BString fIconFile;
entry_ref fFileRef; entry_ref fFileRef;
char* fMessage; BString fContent;
char* fApp; BString fOnClickApp;
bool fHasFile; bool fHasFile;
entry_ref fFile; entry_ref fFile;
BList* fRefs; BList* fRefs;
@ -76,14 +74,8 @@ NotifyApp::NotifyApp()
BApplication(kSignature), BApplication(kSignature),
fHasGoodArguments(false), fHasGoodArguments(false),
fType(B_INFORMATION_NOTIFICATION), fType(B_INFORMATION_NOTIFICATION),
fAppName(NULL),
fTitle(NULL),
fMsgId(NULL),
fProgress(0.0f), fProgress(0.0f),
fTimeout(0), fTimeout(-1),
fIconFile(NULL),
fMessage(NULL),
fApp(NULL),
fHasFile(false) fHasFile(false)
{ {
fRefs = new BList(); fRefs = new BList();
@ -93,19 +85,12 @@ NotifyApp::NotifyApp()
NotifyApp::~NotifyApp() NotifyApp::~NotifyApp()
{ {
free(fAppName);
free(fTitle);
free(fMsgId);
free(fIconFile);
free(fMessage);
free(fApp);
for (int32 i = 0; void* item = fRefs->ItemAt(i); i++) for (int32 i = 0; void* item = fRefs->ItemAt(i); i++)
delete (BEntry*)item; delete (BEntry*)item;
delete fRefs; delete fRefs;
for (int32 i = 0; void* item = fArgv->ItemAt(i); i++) for (int32 i = 0; void* item = fArgv->ItemAt(i); i++)
free(item); delete (BString*)item;
delete fArgv; delete fArgv;
} }
@ -134,25 +119,25 @@ NotifyApp::ArgvReceived(int32 argc, char** argv)
if (strncmp(kTypeNames[i], argument, strlen(argument)) == 0) if (strncmp(kTypeNames[i], argument, strlen(argument)) == 0)
fType = (notification_type)i; fType = (notification_type)i;
} }
} else if (strcmp(option, "app") == 0) } else if (strcmp(option, "group") == 0)
fAppName = strdup(argument); fGroup = argument;
else if (strcmp(option, "title") == 0) else if (strcmp(option, "title") == 0)
fTitle = strdup(argument); fTitle = argument;
else if (strcmp(option, "messageID") == 0) else if (strcmp(option, "messageID") == 0)
fMsgId = strdup(argument); fMsgId = argument;
else if (strcmp(option, "progress") == 0) else if (strcmp(option, "progress") == 0)
fProgress = atof(argument); fProgress = atof(argument);
else if (strcmp(option, "timeout") == 0) else if (strcmp(option, "timeout") == 0)
fTimeout = atol(argument) * 1000000; fTimeout = atol(argument) * 1000000;
else if (strcmp(option, "icon") == 0) { else if (strcmp(option, "icon") == 0) {
fIconFile = strdup(argument); fIconFile = argument;
if (get_ref_for_path(fIconFile, &fFileRef) < B_OK) { if (get_ref_for_path(fIconFile.String(), &fFileRef) < B_OK) {
fprintf(stderr, "Bad icon path!\n\n"); fprintf(stderr, "Bad icon path!\n\n");
return; return;
} }
} else if (strcmp(option, "onClickApp") == 0) } else if (strcmp(option, "onClickApp") == 0)
fApp = strdup(argument); fOnClickApp = argument;
else if (strcmp(option, "onClickFile") == 0) { else if (strcmp(option, "onClickFile") == 0) {
if (get_ref_for_path(argument, &fFile) != B_OK) { if (get_ref_for_path(argument, &fFile) != B_OK) {
fprintf(stderr, "Bad path for --onClickFile!\n\n"); fprintf(stderr, "Bad path for --onClickFile!\n\n");
@ -170,7 +155,7 @@ NotifyApp::ArgvReceived(int32 argc, char** argv)
fRefs->AddItem(new BEntry(&ref)); fRefs->AddItem(new BEntry(&ref));
} else if (strcmp(option, "onClickArgv") == 0) } else if (strcmp(option, "onClickArgv") == 0)
fArgv->AddItem(strdup(argument)); fArgv->AddItem(new BString(argument));
else { else {
// Unrecognized option // Unrecognized option
fprintf(stderr, "Unrecognized option --%s\n\n", option); fprintf(stderr, "Unrecognized option --%s\n\n", option);
@ -188,17 +173,7 @@ NotifyApp::ArgvReceived(int32 argc, char** argv)
} }
} }
// Check for missing arguments fContent = argv[index];
if (fAppName == NULL) {
fprintf(stderr, "Missing --app argument!\n\n");
return;
}
if (fTitle == NULL) {
fprintf(stderr, "Missing --title argument!\n\n");
return;
}
fMessage = strdup(argv[index]);
fHasGoodArguments = true; fHasGoodArguments = true;
} }
@ -208,13 +183,13 @@ NotifyApp::_Usage() const
fprintf(stderr, "Usage: notify [OPTION]... [MESSAGE]\n" fprintf(stderr, "Usage: notify [OPTION]... [MESSAGE]\n"
"Send notifications to notification_server.\n" "Send notifications to notification_server.\n"
" --type <type>\tNotification type,\n" " --type <type>\tNotification type,\n"
" \t <type>: "); " \t <type> - \"information\" is assumed by default: ");
for (int32 i = 0; kTypeNames[i]; i++) for (int32 i = 0; kTypeNames[i]; i++)
fprintf(stderr, kTypeNames[i + 1] ? "%s|" : "%s\n", kTypeNames[i]); fprintf(stderr, kTypeNames[i + 1] ? "%s|" : "%s\n", kTypeNames[i]);
fprintf(stderr, fprintf(stderr,
" --app <app name>\tApplication name\n" " --group <group>\tGroup\n"
" --title <title>\tMessage title\n" " --title <title>\tMessage title\n"
" --messageID <msg id>\tMessage ID\n" " --messageID <msg id>\tMessage ID\n"
" --progress <float>\tProgress, value between 0.0 and 1.0 - if type is set to progress\n" " --progress <float>\tProgress, value between 0.0 and 1.0 - if type is set to progress\n"
@ -256,17 +231,20 @@ NotifyApp::ReadyToRun()
{ {
if (HasGoodArguments()) { if (HasGoodArguments()) {
BNotification notification(fType); BNotification notification(fType);
notification.SetApplication(fAppName); if (fGroup != "")
notification.SetGroup(fGroup);
if (fTitle != "")
notification.SetTitle(fTitle); notification.SetTitle(fTitle);
notification.SetContent(fMessage); if (fContent != "")
notification.SetContent(fContent);
if (fMsgId != NULL) if (fMsgId != "")
notification.SetMessageID(fMsgId); notification.SetMessageID(fMsgId);
if (fType == B_PROGRESS_NOTIFICATION) if (fType == B_PROGRESS_NOTIFICATION)
notification.SetProgress(fProgress); notification.SetProgress(fProgress);
if (fIconFile != NULL) { if (fIconFile != "") {
BBitmap* bitmap = _GetBitmap(&fFileRef); BBitmap* bitmap = _GetBitmap(&fFileRef);
if (bitmap) { if (bitmap) {
notification.SetIcon(bitmap); notification.SetIcon(bitmap);
@ -274,8 +252,8 @@ NotifyApp::ReadyToRun()
} }
} }
if (fApp != NULL) if (fOnClickApp != "")
notification.SetOnClickApp(fApp); notification.SetOnClickApp(fOnClickApp);
if (fHasFile) if (fHasFile)
notification.SetOnClickFile(&fFile); notification.SetOnClickFile(&fFile);
@ -289,11 +267,11 @@ NotifyApp::ReadyToRun()
} }
for (int32 i = 0; void* item = fArgv->ItemAt(i); i++) { for (int32 i = 0; void* item = fArgv->ItemAt(i); i++) {
const char* arg = (const char*)item; BString* arg = (BString*)item;
notification.AddOnClickArg(arg); notification.AddOnClickArg(arg->String());
} }
status_t ret = be_roster->Notify(notification, fTimeout); status_t ret = notification.Send(fTimeout);
if (ret != B_OK) { if (ret != B_OK) {
fprintf(stderr, "Failed to deliver notification: %s\n", fprintf(stderr, "Failed to deliver notification: %s\n",
strerror(ret)); strerror(ret));

View File

@ -27,9 +27,8 @@ AppUsage::AppUsage()
} }
AppUsage::AppUsage(entry_ref ref, const char* name, bool allow) AppUsage::AppUsage(const char* name, bool allow)
: :
fRef(ref),
fName(name), fName(name),
fAllow(allow) fAllow(allow)
{ {
@ -38,7 +37,7 @@ AppUsage::AppUsage(entry_ref ref, const char* name, bool allow)
AppUsage::~AppUsage() AppUsage::~AppUsage()
{ {
notify_t::iterator nIt; notification_t::iterator nIt;
for (nIt = fNotifications.begin(); nIt != fNotifications.end(); nIt++) for (nIt = fNotifications.begin(); nIt != fNotifications.end(); nIt++)
delete nIt->second; delete nIt->second;
} }
@ -55,13 +54,12 @@ status_t
AppUsage::Flatten(void* buffer, ssize_t numBytes) const AppUsage::Flatten(void* buffer, ssize_t numBytes) const
{ {
BMessage msg; BMessage msg;
msg.AddString("app_name", fName); msg.AddString("signature", fName);
msg.AddRef("app_ref", &fRef); msg.AddBool("allow", fAllow);
msg.AddBool("app_allow", fAllow);
notify_t::const_iterator nIt; notification_t::const_iterator nIt;
for (nIt = fNotifications.begin(); nIt != fNotifications.end(); nIt++) for (nIt = fNotifications.begin(); nIt != fNotifications.end(); nIt++)
msg.AddFlat("notify", nIt->second); msg.AddFlat("notification", nIt->second);
if (numBytes < msg.FlattenedSize()) if (numBytes < msg.FlattenedSize())
return B_ERROR; return B_ERROR;
@ -74,13 +72,12 @@ ssize_t
AppUsage::FlattenedSize() const AppUsage::FlattenedSize() const
{ {
BMessage msg; BMessage msg;
msg.AddString("app_name", fName); msg.AddString("signature", fName);
msg.AddRef("app_ref", &fRef); msg.AddBool("allow", fAllow);
msg.AddBool("app_allow", fAllow);
notify_t::const_iterator nIt; notification_t::const_iterator nIt;
for (nIt = fNotifications.begin(); nIt != fNotifications.end(); nIt++) for (nIt = fNotifications.begin(); nIt != fNotifications.end(); nIt++)
msg.AddFlat("notify", nIt->second); msg.AddFlat("notification", nIt->second);
return msg.FlattenedSize(); return msg.FlattenedSize();
} }
@ -113,21 +110,20 @@ AppUsage::Unflatten(type_code code, const void* buffer,
status = msg.Unflatten((const char*)buffer); status = msg.Unflatten((const char*)buffer);
if (status == B_OK) { if (status == B_OK) {
msg.FindString("app_name", &fName); msg.FindString("signature", &fName);
msg.FindRef("app_ref", &fRef); msg.FindBool("allow", &fAllow);
msg.FindBool("app_allow", &fAllow);
type_code type; type_code type;
int32 count = 0; int32 count = 0;
status = msg.GetInfo("notify", &type, &count); status = msg.GetInfo("notification", &type, &count);
if (status != B_OK) if (status != B_OK)
return status; return status;
for (int32 i = 0; i < count; i++) { for (int32 i = 0; i < count; i++) {
NotificationReceived *notify = new NotificationReceived(); NotificationReceived *notification = new NotificationReceived();
msg.FindFlat("notify", i, notify); msg.FindFlat("notification", i, notification);
fNotifications[notify->Title()] = notify; fNotifications[notification->Title()] = notification;
} }
status = B_OK; status = B_OK;
@ -137,13 +133,6 @@ AppUsage::Unflatten(type_code code, const void* buffer,
} }
entry_ref
AppUsage::Ref()
{
return fRef;
}
const char* const char*
AppUsage::Name() AppUsage::Name()
{ {
@ -157,7 +146,7 @@ AppUsage::Allowed(const char* title, notification_type type)
bool allowed = fAllow; bool allowed = fAllow;
if (allowed) { if (allowed) {
notify_t::iterator nIt = fNotifications.find(title); notification_t::iterator nIt = fNotifications.find(title);
if (nIt == fNotifications.end()) { if (nIt == fNotifications.end()) {
allowed = true; allowed = true;
fNotifications[title] = new NotificationReceived(title, type); fNotifications[title] = new NotificationReceived(title, type);
@ -182,7 +171,7 @@ AppUsage::Allowed()
NotificationReceived* NotificationReceived*
AppUsage::NotificationAt(int32 index) AppUsage::NotificationAt(int32 index)
{ {
notify_t::iterator nIt = fNotifications.begin(); notification_t::iterator nIt = fNotifications.begin();
for (int32 i = 0; i < index; i++) for (int32 i = 0; i < index; i++)
nIt++; nIt++;

View File

@ -20,5 +20,3 @@ const char* kTimeoutName = "timeout";
// Display settings // Display settings
const char* kWidthName = "width"; const char* kWidthName = "width";
const char* kIconSizeName = "icon size"; const char* kIconSizeName = "icon size";
const char* kLayoutName = "layout";

View File

@ -191,7 +191,7 @@ MailDaemonApp::ReadyToRun()
fCentralBeep = false; fCentralBeep = false;
fNotification = new BNotification(B_INFORMATION_NOTIFICATION); fNotification = new BNotification(B_INFORMATION_NOTIFICATION);
fNotification->SetApplication(B_TRANSLATE("Mail status")); fNotification->SetGroup(B_TRANSLATE("Mail status"));
fNotification->SetTitle(string); fNotification->SetTitle(string);
fNotification->SetMessageID("daemon_status"); fNotification->SetMessageID("daemon_status");
@ -390,7 +390,7 @@ MailDaemonApp::MessageReceived(BMessage* msg)
fNotification->SetTitle(string.String()); fNotification->SetTitle(string.String());
if (fNotifyMode != B_MAIL_SHOW_STATUS_WINDOW_NEVER) if (fNotifyMode != B_MAIL_SHOW_STATUS_WINDOW_NEVER)
be_roster->Notify(*fNotification); fNotification->Send();
break; break;
} }

View File

@ -42,7 +42,7 @@ DefaultNotifier::DefaultNotifier(const char* accountName, bool inbound,
// Two windows for each acocunt : one for sending and the other for // Two windows for each acocunt : one for sending and the other for
// receiving mails // receiving mails
fNotification.SetMessageID(identifier); fNotification.SetMessageID(identifier);
fNotification.SetApplication(B_TRANSLATE("Mail Status")); fNotification.SetGroup(B_TRANSLATE("Mail Status"));
fNotification.SetTitle(desc); fNotification.SetTitle(desc);
app_info info; app_info info;
@ -127,7 +127,7 @@ DefaultNotifier::ReportProgress(int bytes, int messages, const char* message)
if ((!fIsInbound && fShowMode | B_MAIL_SHOW_STATUS_WINDOW_WHEN_SENDING) if ((!fIsInbound && fShowMode | B_MAIL_SHOW_STATUS_WINDOW_WHEN_SENDING)
|| (fIsInbound && fShowMode | B_MAIL_SHOW_STATUS_WINDOW_WHEN_ACTIVE)) || (fIsInbound && fShowMode | B_MAIL_SHOW_STATUS_WINDOW_WHEN_ACTIVE))
be_roster->Notify(fNotification, timeout); fNotification.Send(timeout);
} }
@ -137,5 +137,5 @@ DefaultNotifier::ResetProgress(const char* message)
fNotification.SetProgress(0); fNotification.SetProgress(0);
if (message != NULL) if (message != NULL)
fNotification.SetTitle(message); fNotification.SetTitle(message);
be_roster->Notify(fNotification, 0); fNotification.Send(0);
} }

View File

@ -13,6 +13,9 @@
#include <algorithm> #include <algorithm>
#include <GroupLayout.h>
#include <GroupView.h>
#include "AppGroupView.h" #include "AppGroupView.h"
#include "NotificationWindow.h" #include "NotificationWindow.h"
@ -21,13 +24,16 @@
AppGroupView::AppGroupView(NotificationWindow* win, const char* label) AppGroupView::AppGroupView(NotificationWindow* win, const char* label)
: :
BView(BRect(0, 0, win->ViewWidth(), 1), label, B_FOLLOW_LEFT_RIGHT, BBox(B_FANCY_BORDER, (fView = new BGroupView(B_VERTICAL, 10))),
B_WILL_DRAW|B_FULL_UPDATE_ON_RESIZE|B_FRAME_EVENTS),
fLabel(label), fLabel(label),
fParent(win), fParent(win),
fCollapsed(false) fCollapsed(false)
{ {
Show(); // If no group was specified we don't have any border or label
if (label == NULL)
SetBorder(B_NO_BORDER);
else
SetLabel(label);
} }
@ -36,6 +42,7 @@ AppGroupView::~AppGroupView()
} }
/*
void void
AppGroupView::AttachedToWindow() AppGroupView::AttachedToWindow()
{ {
@ -43,8 +50,9 @@ AppGroupView::AttachedToWindow()
SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR)); SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
SetHighColor(ui_color(B_PANEL_TEXT_COLOR)); SetHighColor(ui_color(B_PANEL_TEXT_COLOR));
} }
*/
/*
void void
AppGroupView::Draw(BRect updateRect) AppGroupView::Draw(BRect updateRect)
{ {
@ -120,7 +128,7 @@ AppGroupView::Draw(BRect updateRect)
Sync(); Sync();
} }
*/
void void
AppGroupView::MouseDown(BPoint point) AppGroupView::MouseDown(BPoint point)
@ -131,7 +139,7 @@ AppGroupView::MouseDown(BPoint point)
int32 children = fInfo.size(); int32 children = fInfo.size();
for (int32 i = 0; i < children; i++) { for (int32 i = 0; i < children; i++) {
fInfo[i]->RemoveSelf(); fView->GetLayout()->RemoveView(fInfo[i]);
delete fInfo[i]; delete fInfo[i];
} }
fInfo.clear(); fInfo.clear();
@ -143,41 +151,11 @@ AppGroupView::MouseDown(BPoint point)
} }
if (changed) { if (changed) {
ResizeViews(); _ResizeViews();
Invalidate();
} }
} }
void
AppGroupView::GetPreferredSize(float* width, float* height)
{
font_height fh;
be_bold_font->GetHeight(&fh);
float h = fh.ascent + fh.leading + fh.leading;
h += kEdgePadding * 2; // Padding between top and bottom of label
if (!fCollapsed) {
int32 children = fInfo.size();
for (int32 i = 0; i < children; i++) {
float childHeight = 0;
float childWidth = 0;
fInfo[i]->GetPreferredSize(&childWidth, &childHeight);
h += childHeight;
}
}
h += kEdgePadding;
*width = fParent->ViewWidth();
*height = h;
}
void void
AppGroupView::MessageReceived(BMessage* msg) AppGroupView::MessageReceived(BMessage* msg)
{ {
@ -192,16 +170,14 @@ AppGroupView::MessageReceived(BMessage* msg)
if (vIt != fInfo.end()) { if (vIt != fInfo.end()) {
fInfo.erase(vIt); fInfo.erase(vIt);
view->RemoveSelf(); fView->GetLayout()->RemoveView(view);
delete view; delete view;
} }
ResizeViews(); if (Window() != NULL)
Invalidate(); Window()->PostMessage(msg);
// When all the views are destroy, save app filters _ResizeViews();
if (fInfo.size() == 0)
dynamic_cast<NotificationWindow*>(Window())->SaveAppFilters();
break; break;
} }
default: default:
@ -214,13 +190,14 @@ void
AppGroupView::AddInfo(NotificationView* view) AppGroupView::AddInfo(NotificationView* view)
{ {
BString id = view->MessageID(); BString id = view->MessageID();
if (id.Length() > 0) {
int32 children = fInfo.size();
bool found = false; bool found = false;
if (id.Length() > 0) {
int32 children = fInfo.size();
for (int32 i = 0; i < children; i++) { for (int32 i = 0; i < children; i++) {
if (fInfo[i]->HasMessageID(id.String())) { if (id == fInfo[i]->MessageID()) {
fInfo[i]->RemoveSelf(); fView->GetLayout()->RemoveView(fInfo[i]);
delete fInfo[i]; delete fInfo[i];
fInfo[i] = view; fInfo[i] = view;
@ -229,28 +206,23 @@ AppGroupView::AddInfo(NotificationView* view)
break; break;
} }
} }
}
if (!found) if (!found)
fInfo.push_back(view); fInfo.push_back(view);
} else fView->GetLayout()->AddView(view);
fInfo.push_back(view);
if (fParent->IsHidden())
fParent->Show();
if (IsHidden()) if (IsHidden())
Show(); Show();
if (view->IsHidden()) if (view->IsHidden())
view->Show(); view->Show();
AddChild(view); _ResizeViews();
ResizeViews();
Invalidate();
} }
void void
AppGroupView::ResizeViews() AppGroupView::_ResizeViews()
{ {
font_height fh; font_height fh;
be_bold_font->GetHeight(&fh); be_bold_font->GetHeight(&fh);
@ -268,22 +240,14 @@ AppGroupView::ResizeViews()
offset += fInfo[i]->Bounds().Height(); offset += fInfo[i]->Bounds().Height();
if (fInfo[i]->IsHidden()) if (fInfo[i]->IsHidden())
fInfo[i]->Show(); fInfo[i]->Show();
fInfo[i]->SetPosition(false, false); }
};
} else { } else {
for (int32 i = 0; i < children; i++) for (int32 i = 0; i < children; i++)
if (!fInfo[i]->IsHidden()) if (!fInfo[i]->IsHidden())
fInfo[i]->Hide(); fInfo[i]->Hide();
} }
if (children == 1) ResizeTo(fParent->Width(), offset);
fInfo[0]->SetPosition(true, true);
else if (children > 1) {
fInfo[0]->SetPosition(true, false);
fInfo[children - 1]->SetPosition(false, true);
}
ResizeTo(fParent->ViewWidth(), offset);
float labelOffset = fh.ascent + fh.leading; float labelOffset = fh.ascent + fh.leading;
BRect borderRect = Bounds().InsetByCopy(kEdgePadding, kEdgePadding); BRect borderRect = Bounds().InsetByCopy(kEdgePadding, kEdgePadding);
@ -299,8 +263,6 @@ AppGroupView::ResizeViews()
fCloseRect.top += kEdgePadding * 1.5; fCloseRect.top += kEdgePadding * 1.5;
fCloseRect.left = fCloseRect.right - kCloseSize; fCloseRect.left = fCloseRect.right - kCloseSize;
fCloseRect.bottom = fCloseRect.top + kCloseSize; fCloseRect.bottom = fCloseRect.top + kCloseSize;
fParent->ResizeAll();
} }

View File

@ -1,50 +1,47 @@
/* /*
* Copyright 2005-2008, Mikael Eiman. * Copyright 2010, Haiku, Inc. All Rights Reserved.
* Copyright 2005-2008, Michael Davidson. * Copyright 2008-2009, Pier Luigi Fiorini. All Rights Reserved.
* Copyright 2004-2008, Michael Davidson. All Rights Reserved.
* Copyright 2004-2007, Mikael Eiman. All Rights Reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*
* Authors:
* Mikael Eiman <mikael@eiman.tv>
* Michael Davidson <slaad@bong.com.au>
*/ */
#ifndef _APP_GROUP_VIEW_H
#ifndef APPGROUPVIEW_H #define _APP_GROUP_VIEW_H
#define APPGROUPVIEW_H
#include <vector> #include <vector>
#include <Box.h>
#include <String.h> #include <String.h>
#include <View.h>
class BGroupView;
class NotificationWindow; class NotificationWindow;
class NotificationView; class NotificationView;
typedef std::vector<NotificationView*> infoview_t; typedef std::vector<NotificationView*> infoview_t;
class AppGroupView : public BView { class AppGroupView : public BBox {
public: public:
AppGroupView(NotificationWindow* win, const char* label); AppGroupView(NotificationWindow* win, const char* label);
~AppGroupView(void); ~AppGroupView();
// Hooks virtual void MouseDown(BPoint point);
void AttachedToWindow(void); virtual void MessageReceived(BMessage* msg);
void Draw(BRect bounds);
void MouseDown(BPoint point); bool HasChildren();
void GetPreferredSize(float *width, float *height);
void MessageReceived(BMessage *msg);
// Public
void AddInfo(NotificationView* view); void AddInfo(NotificationView* view);
void ResizeViews(void);
bool HasChildren(void);
private: private:
void _ResizeViews();
BString fLabel; BString fLabel;
NotificationWindow* fParent; NotificationWindow* fParent;
BGroupView* fView;
infoview_t fInfo; infoview_t fInfo;
bool fCollapsed; bool fCollapsed;
BRect fCloseRect; BRect fCloseRect;
BRect fCollapseRect; BRect fCollapseRect;
}; };
#endif #endif // _APP_GROUP_VIEW_H

View File

@ -1,114 +0,0 @@
/*
* Copyright 2010, Haiku, Inc. All Rights Reserved.
* Copyright 2008-2009, Pier Luigi Fiorini. All Rights Reserved.
* Copyright 2004-2008, Michael Davidson. All Rights Reserved.
* Copyright 2004-2007, Mikael Eiman. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Davidson, slaad@bong.com.au
* Mikael Eiman, mikael@eiman.tv
* Pier Luigi Fiorini, pierluigi.fiorini@gmail.com
*/
#include "BorderView.h"
const float kBorderWidth = 2.0f;
const int32 kTitleSize = 14;
BorderView::BorderView(BRect rect, const char* text)
:
BView(rect, "NotificationBorderView", B_FOLLOW_ALL,
B_WILL_DRAW | B_FRAME_EVENTS),
fTitle(text)
{
SetViewColor(B_TRANSPARENT_COLOR);
}
BorderView::~BorderView()
{
}
void
BorderView::FrameResized(float, float)
{
Invalidate();
}
void
BorderView::Draw(BRect rect)
{
rgb_color col_bg = ui_color(B_PANEL_BACKGROUND_COLOR);
rgb_color col_text = tint_color(col_bg, B_LIGHTEN_MAX_TINT);
rgb_color col_text_shadow = tint_color(col_bg, B_DARKEN_MAX_TINT);
// Background
SetDrawingMode(B_OP_COPY);
SetHighColor(col_bg);
FillRect(rect);
// Text
SetLowColor(col_bg);
SetDrawingMode(B_OP_ALPHA);
SetFont(be_bold_font);
SetFontSize(kTitleSize);
BFont font;
GetFont(&font);
font_height fh;
font.GetHeight(&fh);
// float line_height = fh.ascent + fh.descent + fh.leading;
float text_pos = fh.ascent;
SetHighColor(col_text);
DrawString(fTitle.String(), BPoint(kBorderWidth, text_pos));
SetHighColor(col_text_shadow);
DrawString(fTitle.String(), BPoint(kBorderWidth + 1, text_pos + 1));
// Content border
SetHighColor(tint_color(col_bg, B_DARKEN_2_TINT));
BRect content = Bounds();
// content.InsetBy(kBorderWidth, kBorderWidth);
content.top += text_pos + fh.descent + 2;
BRect content_line(content);
// content_line.InsetBy(-1, -1);
StrokeRect(content_line);
}
void
BorderView::GetPreferredSize(float* w, float* h)
{
SetFont(be_bold_font);
SetFontSize(kTitleSize);
BFont font;
GetFont(&font);
font_height fh;
font.GetHeight(&fh);
float line_height = fh.ascent + fh.descent;
*w = 2 * kBorderWidth + StringWidth(fTitle.String());
*h = 2 * kBorderWidth + line_height + 3;
*w = *h = 0;
}
float
BorderView::BorderSize()
{
return 0;
}

View File

@ -1,31 +0,0 @@
/*
* Copyright 2010, Haiku, Inc. All Rights Reserved.
* Copyright 2008-2009, Pier Luigi Fiorini. All Rights Reserved.
* Copyright 2004-2008, Michael Davidson. All Rights Reserved.
* Copyright 2004-2007, Mikael Eiman. All Rights Reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _BORDER_VIEW_H
#define _BORDER_VIEW_H
#include <View.h>
#include <String.h>
class BorderView : public BView {
public:
BorderView(BRect, const char*);
virtual ~BorderView();
virtual void Draw(BRect updateRect);
virtual void GetPreferredSize(float*, float*);
virtual void FrameResized(float, float);
float BorderSize();
private:
BString fTitle;
};
#endif // _BORDER_VIEW_H

View File

@ -4,11 +4,10 @@ UsePrivateHeaders notification ;
Server notification_server : Server notification_server :
AppGroupView.cpp AppGroupView.cpp
BorderView.cpp
NotificationServer.cpp NotificationServer.cpp
NotificationView.cpp NotificationView.cpp
NotificationWindow.cpp NotificationWindow.cpp
: be $(TARGET_LIBSTDC++) libicon.a libnotification.a $(HAIKU_LOCALE_LIBS) : be translation $(TARGET_LIBSTDC++) libnotification.a $(HAIKU_LOCALE_LIBS)
: notification_server.rdef : notification_server.rdef
; ;
@ -20,5 +19,4 @@ DoCatalogs notification_server :
NotificationWindow.cpp NotificationWindow.cpp
; ;
Depends notification_server : libicon.a ;
Depends notification_server : libnotification.a ; Depends notification_server : libnotification.a ;

View File

@ -24,7 +24,6 @@ const char* kSoundNames[] = {
NotificationServer::NotificationServer() NotificationServer::NotificationServer()
: BApplication(kNotificationServerSignature) : BApplication(kNotificationServerSignature)
{ {
fWindow = new NotificationWindow();
} }
@ -33,6 +32,13 @@ NotificationServer::~NotificationServer()
} }
void
NotificationServer::ReadyToRun()
{
fWindow = new NotificationWindow();
}
void void
NotificationServer::MessageReceived(BMessage* message) NotificationServer::MessageReceived(BMessage* message)
{ {
@ -61,17 +67,6 @@ NotificationServer::MessageReceived(BMessage* message)
} }
bool
NotificationServer::QuitRequested()
{
if (fWindow && fWindow->Lock()) {
fWindow->Quit();
fWindow = NULL;
}
return true;
}
status_t status_t
NotificationServer::GetSupportedSuites(BMessage* msg) NotificationServer::GetSupportedSuites(BMessage* msg)
{ {
@ -110,8 +105,8 @@ main(int argc, char* argv[])
add_system_beep_event(kSoundNames[i++], 0); add_system_beep_event(kSoundNames[i++], 0);
// Start! // Start!
NotificationServer* server = new NotificationServer(); NotificationServer server;
server->Run(); server.Run();
return 0; return 0;
} }

View File

@ -14,8 +14,8 @@ public:
NotificationServer(); NotificationServer();
virtual ~NotificationServer(); virtual ~NotificationServer();
virtual void ReadyToRun();
virtual void MessageReceived(BMessage* message); virtual void MessageReceived(BMessage* message);
virtual bool QuitRequested();
virtual status_t GetSupportedSuites(BMessage* msg); virtual status_t GetSupportedSuites(BMessage* msg);
virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* spec, virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* spec,

View File

@ -13,28 +13,16 @@
* Adrien Destugues <pulkomandy@pulkomandy.ath.cx> * Adrien Destugues <pulkomandy@pulkomandy.ath.cx>
*/ */
#include <stdlib.h>
#include <ControlLook.h> #include <ControlLook.h>
#include <Font.h> #include <LayoutUtils.h>
#include <IconUtils.h>
#include <Messenger.h> #include <Messenger.h>
#include <Picture.h> #include <Path.h>
#include <PropertyInfo.h>
#include <Region.h>
#include <Resources.h>
#include <Roster.h> #include <Roster.h>
#include <StatusBar.h> #include <StatusBar.h>
#include <StringView.h>
#include <TranslationUtils.h>
#include "NotificationView.h" #include "NotificationView.h"
#include "NotificationWindow.h" #include "NotificationWindow.h"
const char* kSmallIconAttribute = "BEOS:M:STD_ICON";
const char* kLargeIconAttribute = "BEOS:L:STD_ICON";
const char* kIconAttribute = "BEOS:ICON";
static const int kIconStripeWidth = 32; static const int kIconStripeWidth = 32;
property_info message_prop_list[] = { property_info message_prop_list[] = {
@ -55,46 +43,25 @@ property_info message_prop_list[] = {
NotificationView::NotificationView(NotificationWindow* win, NotificationView::NotificationView(NotificationWindow* win,
notification_type type, const char* app, const char* title, const char* text, BNotification* notification, bigtime_t timeout)
BMessage* details)
: :
BView(BRect(0, 0, win->ViewWidth(), 1), "NotificationView", BView("NotificationView", B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE
B_FOLLOW_LEFT_RIGHT, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE
| B_FRAME_EVENTS), | B_FRAME_EVENTS),
fParent(win), fParent(win),
fType(type), fNotification(notification),
fTimeout(timeout),
fRunner(NULL), fRunner(NULL),
fProgress(0.0f), fBitmap(NULL)
fMessageID(""),
fDetails(details),
fBitmap(NULL),
fIsFirst(false),
fIsLast(false)
{ {
BMessage iconMsg; if (fNotification->Icon() != NULL)
if (fDetails->FindMessage("icon", &iconMsg) == B_OK) fBitmap = new BBitmap(fNotification->Icon());
fBitmap = new BBitmap(&iconMsg);
if (!fBitmap) if (fTimeout <= 0)
_LoadIcon(); fTimeout = fParent->Timeout() * 1000000;
const char* messageID = NULL; SetText();
if (fDetails->FindString("messageID", &messageID) == B_OK)
fMessageID = messageID;
if (fDetails->FindFloat("progress", &fProgress) != B_OK) switch (fNotification->Type()) {
fProgress = 0.0f;
// Progress is between 0 and 1
if (fProgress < 0.0f)
fProgress = 0.0f;
if (fProgress > 1.0f)
fProgress = 1.0f;
SetText(app, title, text);
ResizeToPreferred();
switch (type) {
case B_IMPORTANT_NOTIFICATION: case B_IMPORTANT_NOTIFICATION:
SetViewColor(255, 255, 255); SetViewColor(255, 255, 255);
SetLowColor(255, 255, 255); SetLowColor(255, 255, 255);
@ -110,18 +77,18 @@ NotificationView::NotificationView(NotificationWindow* win,
BStatusBar* progress = new BStatusBar(frame, "progress"); BStatusBar* progress = new BStatusBar(frame, "progress");
progress->SetBarHeight(12.0f); progress->SetBarHeight(12.0f);
progress->SetMaxValue(1.0f); progress->SetMaxValue(1.0f);
progress->Update(fProgress); progress->Update(fNotification->Progress());
BString label = ""; BString label = "";
label << (int)(fProgress * 100) << " %"; label << (int)(fNotification->Progress() * 100) << " %";
progress->SetTrailingText(label); progress->SetTrailingText(label);
AddChild(progress); AddChild(progress);
} }
// fall through
default: default:
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR)); SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
break;
} }
} }
@ -129,8 +96,8 @@ NotificationView::NotificationView(NotificationWindow* win,
NotificationView::~NotificationView() NotificationView::~NotificationView()
{ {
delete fRunner; delete fRunner;
delete fDetails;
delete fBitmap; delete fBitmap;
delete fNotification;
LineInfoList::iterator lIt; LineInfoList::iterator lIt;
for (lIt = fLines.begin(); lIt != fLines.end(); lIt++) for (lIt = fLines.begin(); lIt != fLines.end(); lIt++)
@ -143,13 +110,8 @@ NotificationView::AttachedToWindow()
{ {
BMessage msg(kRemoveView); BMessage msg(kRemoveView);
msg.AddPointer("view", this); msg.AddPointer("view", this);
bigtime_t timeout = -1;
if (fDetails->FindInt64("timeout", &timeout) != B_OK) fRunner = new BMessageRunner(BMessenger(Parent()), &msg, fTimeout, 1);
timeout = fParent->Timeout() * 1000000;
if (timeout > 0)
fRunner = new BMessageRunner(BMessenger(Parent()), &msg, timeout, 1);
} }
@ -171,19 +133,19 @@ NotificationView::MessageReceived(BMessage* msg)
if (msgOkay) { if (msgOkay) {
if (strcmp(property, "type") == 0) if (strcmp(property, "type") == 0)
reply.AddInt32("result", fType); reply.AddInt32("result", fNotification->Type());
if (strcmp(property, "app") == 0) if (strcmp(property, "group") == 0)
reply.AddString("result", fApp); reply.AddString("result", fNotification->Group());
if (strcmp(property, "title") == 0) if (strcmp(property, "title") == 0)
reply.AddString("result", fTitle); reply.AddString("result", fNotification->Title());
if (strcmp(property, "content") == 0) if (strcmp(property, "content") == 0)
reply.AddString("result", fText); reply.AddString("result", fNotification->Content());
if (strcmp(property, "progress") == 0) if (strcmp(property, "progress") == 0)
reply.AddFloat("result", fProgress); reply.AddFloat("result", fNotification->Progress());
if ((strcmp(property, "icon") == 0) && fBitmap) { if ((strcmp(property, "icon") == 0) && fBitmap) {
BMessage archive; BMessage archive;
@ -213,14 +175,19 @@ NotificationView::MessageReceived(BMessage* msg)
msgOkay = false; msgOkay = false;
if (msgOkay) { if (msgOkay) {
if (strcmp(property, "app") == 0) const char* value = NULL;
msg->FindString("data", &fApp);
if (strcmp(property, "group") == 0)
if (msg->FindString("data", &value) == B_OK)
fNotification->SetGroup(value);
if (strcmp(property, "title") == 0) if (strcmp(property, "title") == 0)
msg->FindString("data", &fTitle); if (msg->FindString("data", &value) == B_OK)
fNotification->SetTitle(value);
if (strcmp(property, "content") == 0) if (strcmp(property, "content") == 0)
msg->FindString("data", &fText); if (msg->FindString("data", &value) == B_OK)
fNotification->SetContent(value);
if (strcmp(property, "icon") == 0) { if (strcmp(property, "icon") == 0) {
BMessage archive; BMessage archive;
@ -230,7 +197,7 @@ NotificationView::MessageReceived(BMessage* msg)
} }
} }
SetText(Application(), Title(), Text()); SetText();
Invalidate(); Invalidate();
reply.AddInt32("error", B_OK); reply.AddInt32("error", B_OK);
@ -242,33 +209,12 @@ NotificationView::MessageReceived(BMessage* msg)
msg->SendReply(&reply); msg->SendReply(&reply);
break; break;
} }
case kRemoveView:
{
BMessage remove(kRemoveView);
remove.AddPointer("view", this);
BMessenger msgr(Window());
msgr.SendMessage( &remove );
break;
}
default: default:
BView::MessageReceived(msg); BView::MessageReceived(msg);
} }
} }
void
NotificationView::GetPreferredSize(float* w, float* h)
{
*w = fParent->ViewWidth();
*h = fHeight;
if (fType == B_PROGRESS_NOTIFICATION) {
*h += 16 + kEdgePadding;
// 16 is progress bar default size as stated in the BeBook
}
}
void void
NotificationView::Draw(BRect updateRect) NotificationView::Draw(BRect updateRect)
{ {
@ -295,7 +241,7 @@ NotificationView::Draw(BRect updateRect)
float iy = (Bounds().Height() - iconSize) / 4.0; float iy = (Bounds().Height() - iconSize) / 4.0;
// Icon is vertically centered in view // Icon is vertically centered in view
if (fType == B_PROGRESS_NOTIFICATION) if (fNotification->Type() == B_PROGRESS_NOTIFICATION)
{ {
// Move icon up by half progress bar height if it's present // Move icon up by half progress bar height if it's present
iy -= (progRect.Height() + kEdgePadding); iy -= (progRect.Height() + kEdgePadding);
@ -363,46 +309,44 @@ NotificationView::MouseDown(BPoint point)
BList messages; BList messages;
entry_ref ref; entry_ref ref;
if (fDetails->FindString("onClickApp", &launchString) == B_OK) if (fNotification->OnClickApp() != NULL
if (be_roster->FindApp(launchString.String(), &appRef) == B_OK) && be_roster->FindApp(fNotification->OnClickApp(), &appRef)
useArgv = true; == B_OK) {
if (fDetails->FindRef("onClickFile", &launchRef) == B_OK) {
if (be_roster->FindApp(&launchRef, &appRef) == B_OK)
useArgv = true; useArgv = true;
} }
if (fDetails->FindRef("onClickRef", &ref) == B_OK) { if (fNotification->OnClickFile() != NULL
for (int32 i = 0; fDetails->FindRef("onClickRef", i, &ref) == B_OK; i++) && be_roster->FindApp(
refMsg.AddRef("refs", &ref); (entry_ref*)fNotification->OnClickFile(), &appRef)
== B_OK) {
useArgv = true;
}
for (int32 i = 0; i < fNotification->CountOnClickRefs(); i++)
refMsg.AddRef("refs", fNotification->OnClickRefAt(i));
messages.AddItem((void*)&refMsg); messages.AddItem((void*)&refMsg);
}
if (useArgv) { if (useArgv) {
type_code type; int32 argc = fNotification->CountOnClickArgs() + 1;
int32 argc = 0;
BString arg; BString arg;
BPath p(&appRef); BPath p(&appRef);
argMsg.AddString("argv", p.Path()); argMsg.AddString("argv", p.Path());
fDetails->GetInfo("onClickArgv", &type, &argc); argMsg.AddInt32("argc", argc);
argMsg.AddInt32("argc", argc + 1);
for (int32 i = 0; fDetails->FindString("onClickArgv", i, &arg) == B_OK; i++) for (int32 i = 0; i < argc - 1; i++) {
argMsg.AddString("argv", arg); argMsg.AddString("argv",
fNotification->OnClickArgAt(i));
}
messages.AddItem((void*)&argMsg); messages.AddItem((void*)&argMsg);
} }
BMessage tmp; if (fNotification->OnClickApp() != NULL)
for (int32 i = 0; fDetails->FindMessage("onClickMsg", i, &tmp) == B_OK; i++) be_roster->Launch(fNotification->OnClickApp(), &messages);
messages.AddItem((void*)&tmp);
if (fDetails->FindString("onClickApp", &launchString) == B_OK)
be_roster->Launch(launchString.String(), &messages);
else else
be_roster->Launch(&launchRef, &messages); be_roster->Launch(fNotification->OnClickFile(), &messages);
} }
// Remove the info view after a click // Remove the info view after a click
@ -417,15 +361,31 @@ NotificationView::MouseDown(BPoint point)
} }
void BSize
NotificationView::FrameResized( float w, float /*h*/) NotificationView::MinSize()
{ {
SetText(Application(), Title(), Text()); return BLayoutUtils::ComposeSize(ExplicitMinSize(), _CalculateSize());
}
BSize
NotificationView::MaxSize()
{
return BLayoutUtils::ComposeSize(ExplicitMaxSize(), _CalculateSize());
}
BSize
NotificationView::PreferredSize()
{
return BLayoutUtils::ComposeSize(ExplicitPreferredSize(),
_CalculateSize());
} }
BHandler* BHandler*
NotificationView::ResolveSpecifier(BMessage* msg, int32 index, BMessage* spec, int32 form, const char* prop) NotificationView::ResolveSpecifier(BMessage* msg, int32 index, BMessage* spec,
int32 form, const char* prop)
{ {
BPropertyInfo prop_info(message_prop_list); BPropertyInfo prop_info(message_prop_list);
if (prop_info.FindMatch(msg, index, spec, form, prop) >= 0) { if (prop_info.FindMatch(msg, index, spec, form, prop) >= 0) {
@ -447,30 +407,8 @@ NotificationView::GetSupportedSuites(BMessage* msg)
} }
const char*
NotificationView::Application() const
{
return fApp.Length() > 0 ? fApp.String() : NULL;
}
const char*
NotificationView::Title() const
{
return fTitle.Length() > 0 ? fTitle.String() : NULL;
}
const char*
NotificationView::Text() const
{
return fText.Length() > 0 ? fText.String() : NULL;
}
void void
NotificationView::SetText(const char* app, const char* title, const char* text, NotificationView::SetText(float newMaxWidth)
float newMaxWidth)
{ {
if (newMaxWidth < 0) if (newMaxWidth < 0)
newMaxWidth = Bounds().Width() - (kEdgePadding * 2); newMaxWidth = Bounds().Width() - (kEdgePadding * 2);
@ -481,10 +419,6 @@ NotificationView::SetText(const char* app, const char* title, const char* text,
delete (*lIt); delete (*lIt);
fLines.clear(); fLines.clear();
fApp = app;
fTitle = title;
fText = text;
float iconRight = kIconStripeWidth; float iconRight = kIconStripeWidth;
if (fBitmap != NULL) if (fBitmap != NULL)
iconRight += fParent->IconSize(); iconRight += fParent->IconSize();
@ -499,7 +433,7 @@ NotificationView::SetText(const char* app, const char* title, const char* text,
// Title // Title
LineInfo* titleLine = new LineInfo; LineInfo* titleLine = new LineInfo;
titleLine->text = fTitle; titleLine->text = fNotification->Title();
titleLine->font = *be_bold_font; titleLine->font = *be_bold_font;
titleLine->location = BPoint(iconRight, y); titleLine->location = BPoint(iconRight, y);
@ -514,7 +448,7 @@ NotificationView::SetText(const char* app, const char* title, const char* text,
// Split text into chunks between certain characters and compose the lines. // Split text into chunks between certain characters and compose the lines.
const char kSeparatorCharacters[] = " \n-\\/"; const char kSeparatorCharacters[] = " \n-\\/";
BString textBuffer = fText; BString textBuffer = fNotification->Content();
textBuffer.ReplaceAll("\t", " "); textBuffer.ReplaceAll("\t", " ");
const char* chunkStart = textBuffer.String(); const char* chunkStart = textBuffer.String();
float maxWidth = newMaxWidth - kEdgePadding - iconRight; float maxWidth = newMaxWidth - kEdgePadding - iconRight;
@ -523,8 +457,7 @@ NotificationView::SetText(const char* app, const char* title, const char* text,
while (chunkStart - textBuffer.String() < length) { while (chunkStart - textBuffer.String() < length) {
size_t chunkLength = strcspn(chunkStart, kSeparatorCharacters) + 1; size_t chunkLength = strcspn(chunkStart, kSeparatorCharacters) + 1;
// Start a new line if either we didn't start one before, // Start a new line if we didn't start one before
// the current offset
BString tempText; BString tempText;
if (line != NULL) if (line != NULL)
tempText.SetTo(line->text); tempText.SetTo(line->text);
@ -539,20 +472,21 @@ NotificationView::SetText(const char* app, const char* title, const char* text,
fLines.push_front(line); fLines.push_front(line);
y += fontHeight; y += fontHeight;
// Skip the eventual new-line character at the beginning of this // Skip the eventual new-line character at the beginning of this chunk
// chunk.
if (chunkStart[0] == '\n') { if (chunkStart[0] == '\n') {
chunkStart++; chunkStart++;
chunkLength--; chunkLength--;
} }
// Skip more new-line characters and move the line further down.
// Skip more new-line characters and move the line further down
while (chunkStart[0] == '\n') { while (chunkStart[0] == '\n') {
chunkStart++; chunkStart++;
chunkLength--; chunkLength--;
line->location.y += fontHeight; line->location.y += fontHeight;
y += fontHeight; y += fontHeight;
} }
// Strip space at beginning of a new line.
// Strip space at beginning of a new line
while (chunkStart[0] == ' ') { while (chunkStart[0] == ' ') {
chunkLength--; chunkLength--;
chunkStart++; chunkStart++;
@ -563,7 +497,7 @@ NotificationView::SetText(const char* app, const char* title, const char* text,
break; break;
// Append the chunk to the current line, which was either a new // Append the chunk to the current line, which was either a new
// line or the one from the previous iteration. // line or the one from the previous iteration
line->text.Append(chunkStart, chunkLength); line->text.Append(chunkStart, chunkLength);
chunkStart += chunkLength; chunkStart += chunkLength;
@ -573,130 +507,36 @@ NotificationView::SetText(const char* app, const char* title, const char* text,
// Make sure icon fits // Make sure icon fits
if (fBitmap != NULL) { if (fBitmap != NULL) {
float minHeight = 0; float minHeight = fBitmap->Bounds().Height() + 2 * kEdgePadding;
if (fParent->Layout() == TitleAboveIcon) {
LineInfo* appLine = fLines.back();
font_height fh;
appLine->font.GetHeight(&fh);
minHeight = appLine->location.y + fh.descent;
}
minHeight += fBitmap->Bounds().Height() + 2 * kEdgePadding;
if (fHeight < minHeight) if (fHeight < minHeight)
fHeight = minHeight; fHeight = minHeight;
} }
BMessenger messenger(Parent());
messenger.SendMessage(kResizeToFit);
}
bool
NotificationView::HasMessageID(const char* id)
{
return fMessageID == id;
} }
const char* const char*
NotificationView::MessageID() NotificationView::MessageID() const
{ {
return fMessageID.String(); return fNotification->MessageID();
} }
void BSize
NotificationView::SetPosition(bool first, bool last) NotificationView::_CalculateSize()
{ {
fIsFirst = first; BSize size;
fIsLast = last;
// Parent width, minus the edge padding, minus the pensize
size.width = fParent->Width() - (kEdgePadding * 2) - (kPenSize * 2);
size.height = fHeight;
if (fNotification->Type() == B_PROGRESS_NOTIFICATION) {
font_height fh;
be_plain_font->GetHeight(&fh);
float fontHeight = fh.ascent + fh.descent + fh.leading;
size.height += (kSmallPadding * 2) + (kEdgePadding * 1) + fontHeight;
} }
return size;
BBitmap*
NotificationView::_ReadNodeIcon(const char* fileName, icon_size size)
{
BEntry entry(fileName, true);
entry_ref ref;
entry.GetRef(&ref);
BNode node(BPath(&ref).Path());
BBitmap* ret = new BBitmap(BRect(0, 0, (float)size - 1, (float)size - 1), B_RGBA32);
if (BIconUtils::GetIcon(&node, kIconAttribute, kSmallIconAttribute,
kLargeIconAttribute, size, ret) != B_OK) {
delete ret;
ret = NULL;
}
return ret;
}
void
NotificationView::_LoadIcon()
{
// First try to get the icon from the caller application
app_info info;
BMessenger msgr = fDetails->ReturnAddress();
if (msgr.IsValid())
be_roster->GetRunningAppInfo(msgr.Team(), &info);
else if (fType == B_PROGRESS_NOTIFICATION)
be_roster->GetAppInfo("application/x-vnd.Haiku-notification_server",
&info);
BPath path;
path.SetTo(&info.ref);
fBitmap = _ReadNodeIcon(path.Path(), fParent->IconSize());
if (fBitmap)
return;
// If that failed get icons from app_server
if (find_directory(B_BEOS_SERVERS_DIRECTORY, &path) != B_OK)
return;
path.Append("app_server");
BFile file(path.Path(), B_READ_ONLY);
if (file.InitCheck() != B_OK)
return;
BResources res(&file);
if (res.InitCheck() != B_OK)
return;
// Which one should we choose?
const char* iconName = "";
switch (fType) {
case B_INFORMATION_NOTIFICATION:
iconName = "info";
break;
case B_ERROR_NOTIFICATION:
iconName = "stop";
break;
case B_IMPORTANT_NOTIFICATION:
iconName = "warn";
break;
default:
return;
}
// Allocate the bitmap
fBitmap = new BBitmap(BRect(0, 0, (float)B_LARGE_ICON - 1,
(float)B_LARGE_ICON - 1), B_RGBA32);
if (!fBitmap || fBitmap->InitCheck() != B_OK) {
fBitmap = NULL;
return;
}
// Load raw icon data
size_t size = 0;
const uint8* data = (const uint8*)res.LoadResource(B_VECTOR_ICON_TYPE,
iconName, &size);
if ((data == NULL
|| BIconUtils::GetVectorIcon(data, size, fBitmap) != B_OK))
fBitmap = NULL;
} }

View File

@ -11,15 +11,8 @@
#include <list> #include <list>
#include <Bitmap.h> #include <Bitmap.h>
#include <Entry.h>
#include <Message.h>
#include <MessageRunner.h> #include <MessageRunner.h>
#include <MimeType.h>
#include <Notification.h> #include <Notification.h>
#include <Path.h>
#include <Roster.h>
#include <String.h>
#include <TextView.h>
#include <View.h> #include <View.h>
class NotificationWindow; class NotificationWindow;
@ -29,39 +22,31 @@ const uint32 kRemoveView = 'ReVi';
class NotificationView : public BView { class NotificationView : public BView {
public: public:
NotificationView(NotificationWindow* win, NotificationView(NotificationWindow* win,
notification_type type, BNotification* notification,
const char* app, const char* title, bigtime_t timeout = -1);
const char* text, BMessage* details);
virtual ~NotificationView(); virtual ~NotificationView();
virtual void AttachedToWindow(); virtual void AttachedToWindow();
virtual void MessageReceived(BMessage* message); virtual void MessageReceived(BMessage* message);
virtual void GetPreferredSize(float* width, float* height);
virtual void Draw(BRect updateRect); virtual void Draw(BRect updateRect);
virtual void MouseDown(BPoint point); virtual void MouseDown(BPoint point);
virtual void FrameResized(float width, float height);
virtual BSize MinSize();
virtual BSize MaxSize();
virtual BSize PreferredSize();
virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index,
BMessage* specifier, int32 form, BMessage* specifier, int32 form,
const char* property); const char* property);
virtual status_t GetSupportedSuites(BMessage* msg); virtual status_t GetSupportedSuites(BMessage* msg);
const char* Application() const; void SetText(float newMaxWidth = -1);
const char* Title() const;
const char* Text() const;
void SetText(const char* app, const char* title, const char* MessageID() const;
const char* text, float newMaxWidth = -1);
bool HasMessageID(const char* id);
const char* MessageID();
void SetPosition(bool first, bool last);
private: private:
BBitmap* _ReadNodeIcon(const char* fileName, BSize _CalculateSize();
icon_size size);
void _LoadIcon();
private:
struct LineInfo { struct LineInfo {
BFont font; BFont font;
BString text; BString text;
@ -70,27 +55,17 @@ private:
typedef std::list<LineInfo*> LineInfoList; typedef std::list<LineInfo*> LineInfoList;
NotificationWindow* fParent; NotificationWindow* fParent;
BNotification* fNotification;
bigtime_t fTimeout;
notification_type fType;
BMessageRunner* fRunner; BMessageRunner* fRunner;
float fProgress;
BString fMessageID;
BMessage* fDetails;
BBitmap* fBitmap; BBitmap* fBitmap;
LineInfoList fLines; LineInfoList fLines;
BString fApp;
BString fTitle;
BString fText;
float fHeight; float fHeight;
bool fIsFirst;
bool fIsLast;
}; };
#endif // _NOTIFICATION_VIEW_H #endif // _NOTIFICATION_VIEW_H

View File

@ -19,15 +19,17 @@
#include <Alert.h> #include <Alert.h>
#include <Application.h> #include <Application.h>
#include <Catalog.h> #include <Catalog.h>
#include <Debug.h>
#include <File.h> #include <File.h>
#include <GroupLayout.h>
#include <GroupLayoutBuilder.h>
#include <Layout.h>
#include <NodeMonitor.h> #include <NodeMonitor.h>
#include <Path.h>
#include <PropertyInfo.h> #include <PropertyInfo.h>
#include <private/interface/WindowPrivate.h> #include <private/interface/WindowPrivate.h>
#include "AppGroupView.h" #include "AppGroupView.h"
#include "AppUsage.h" #include "AppUsage.h"
#include "BorderView.h"
#undef B_TRANSLATE_CONTEXT #undef B_TRANSLATE_CONTEXT
#define B_TRANSLATE_CONTEXT "NotificationWindow" #define B_TRANSLATE_CONTEXT "NotificationWindow"
@ -54,23 +56,19 @@ const float kSmallPadding = 2;
NotificationWindow::NotificationWindow() NotificationWindow::NotificationWindow()
: :
BWindow(BRect(0, 0, 0, 0), B_TRANSLATE_MARK("Notification"), BWindow(BRect(0, 0, -1, -1), B_TRANSLATE_MARK("Notification"),
B_BORDERED_WINDOW_LOOK, B_FLOATING_ALL_WINDOW_FEEL, B_AVOID_FRONT B_BORDERED_WINDOW_LOOK, B_FLOATING_ALL_WINDOW_FEEL, B_AVOID_FRONT
| B_AVOID_FOCUS | B_NOT_CLOSABLE | B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE | B_AVOID_FOCUS | B_NOT_CLOSABLE | B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE
| B_NOT_RESIZABLE | B_NOT_MOVABLE, | B_NOT_RESIZABLE | B_NOT_MOVABLE | B_AUTO_UPDATE_SIZE_LIMITS,
B_ALL_WORKSPACES) B_ALL_WORKSPACES)
{ {
fBorder = new BorderView(Bounds(), "Notification"); SetLayout(new BGroupLayout(B_VERTICAL, 10));
AddChild(fBorder);
// Needed so everything gets the right size - we should switch to layout
// mode...
Show();
Hide(); Hide();
Show();
LoadSettings(true); _LoadSettings(true);
LoadAppFilters(true); _LoadAppFilters(true);
} }
@ -101,7 +99,7 @@ NotificationWindow::WorkspaceActivated(int32 /*workspace*/, bool active)
{ {
// Ensure window is in the correct position // Ensure window is in the correct position
if (active) if (active)
ResizeAll(); _ResizeAll();
} }
@ -111,13 +109,10 @@ NotificationWindow::MessageReceived(BMessage* message)
switch (message->what) { switch (message->what) {
case B_NODE_MONITOR: case B_NODE_MONITOR:
{ {
LoadSettings(); _LoadSettings();
LoadAppFilters(); _LoadAppFilters();
break; break;
} }
case kResizeToFit:
ResizeAll();
break;
case B_COUNT_PROPERTIES: case B_COUNT_PROPERTIES:
{ {
BMessage reply(B_REPLY); BMessage reply(B_REPLY);
@ -145,60 +140,55 @@ NotificationWindow::MessageReceived(BMessage* message)
case B_CREATE_PROPERTY: case B_CREATE_PROPERTY:
case kNotificationMessage: case kNotificationMessage:
{ {
int32 type;
const char* content = NULL;
const char* title = NULL;
const char* app = NULL;
BMessage reply(B_REPLY); BMessage reply(B_REPLY);
bool messageOkay = true; BNotification* notification = new BNotification(message);
if (message->FindInt32("type", &type) != B_OK) if (notification->InitCheck() == B_OK) {
type = B_INFORMATION_NOTIFICATION; bigtime_t timeout;
if (message->FindString("content", &content) != B_OK) if (message->FindInt64("timeout", &timeout) != B_OK)
messageOkay = false; timeout = -1;
if (message->FindString("title", &title) != B_OK)
messageOkay = false;
if (message->FindString("app", &app) != B_OK
&& message->FindString("appTitle", &app) != B_OK)
messageOkay = false;
if (messageOkay) {
NotificationView* view = new NotificationView(this,
(notification_type)type, app, title, content,
new BMessage(*message));
appfilter_t::iterator fIt = fAppFilters.find(app);
bool allow = false;
if (fIt == fAppFilters.end()) {
app_info info;
BMessenger messenger = message->ReturnAddress(); BMessenger messenger = message->ReturnAddress();
app_info info;
if (messenger.IsValid()) if (messenger.IsValid())
be_roster->GetRunningAppInfo(messenger.Team(), &info); be_roster->GetRunningAppInfo(messenger.Team(), &info);
else else
be_roster->GetAppInfo("application/x-vnd.Be-SHEL", &info); be_roster->GetAppInfo("application/x-vnd.Be-SHEL", &info);
AppUsage* appUsage = new AppUsage(info.ref, app, true); NotificationView* view = new NotificationView(this,
fAppFilters[app] = appUsage; notification, timeout);
appUsage->Allowed(title, (notification_type)type); bool allow = false;
appfilter_t::iterator it = fAppFilters.find(info.signature);
if (it == fAppFilters.end()) {
AppUsage* appUsage = new AppUsage(notification->Group(),
true);
appUsage->Allowed(notification->Title(),
notification->Type());
fAppFilters[info.signature] = appUsage;
allow = true; allow = true;
} else } else {
allow = fIt->second->Allowed(title, (notification_type)type); allow = it->second->Allowed(notification->Title(),
notification->Type());
}
if (allow) { if (allow) {
appview_t::iterator aIt = fAppViews.find(app); BString groupName(notification->Group());
appview_t::iterator aIt = fAppViews.find(groupName);
AppGroupView* group = NULL; AppGroupView* group = NULL;
if (aIt == fAppViews.end()) { if (aIt == fAppViews.end()) {
group = new AppGroupView(this, app); group = new AppGroupView(this,
fAppViews[app] = group; groupName == "" ? NULL : groupName.String());
fBorder->AddChild(group); fAppViews[groupName] = group;
GetLayout()->AddView(group);
} else } else
group = aIt->second; group = aIt->second;
group->AddInfo(view); group->AddInfo(view);
ResizeAll(); _ResizeAll();
reply.AddInt32("error", B_OK); reply.AddInt32("error", B_OK);
} else } else
@ -213,22 +203,16 @@ NotificationWindow::MessageReceived(BMessage* message)
} }
case kRemoveView: case kRemoveView:
{ {
void* _ptr; NotificationView* view = NULL;
message->FindPointer("view", &_ptr); if (message->FindPointer("view", (void**)&view) != B_OK)
return;
NotificationView* info views_t::iterator it = find(fViews.begin(), fViews.end(), view);
= reinterpret_cast<NotificationView*>(_ptr);
fBorder->RemoveChild(info); if (it != fViews.end())
fViews.erase(it);
std::vector<NotificationView*>::iterator i _ResizeAll();
= find(fViews.begin(), fViews.end(), info);
if (i != fViews.end())
fViews.erase(i);
delete info;
ResizeAll();
break; break;
} }
default: default:
@ -297,22 +281,15 @@ NotificationWindow::Timeout()
} }
infoview_layout
NotificationWindow::Layout()
{
return fLayout;
}
float float
NotificationWindow::ViewWidth() NotificationWindow::Width()
{ {
return fWidth; return fWidth;
} }
void void
NotificationWindow::ResizeAll() NotificationWindow::_ResizeAll()
{ {
if (fAppViews.empty()) { if (fAppViews.empty()) {
if (!IsHidden()) if (!IsHidden())
@ -365,7 +342,7 @@ NotificationWindow::ResizeAll()
} }
} }
ResizeTo(ViewWidth(), height); ResizeTo(Width(), height);
PopupAnimation(); PopupAnimation();
} }
@ -429,14 +406,14 @@ NotificationWindow::PopupAnimation()
{ {
SetPosition(); SetPosition();
if (IsHidden() && fViews.size() != 0) if (IsHidden())
Show(); Show();
// Activate();// it hides floaters from apps :-( // Activate();// it hides floaters from apps :-(
} }
void void
NotificationWindow::LoadSettings(bool startMonitor) NotificationWindow::_LoadSettings(bool startMonitor)
{ {
_LoadGeneralSettings(startMonitor); _LoadGeneralSettings(startMonitor);
_LoadDisplaySettings(startMonitor); _LoadDisplaySettings(startMonitor);
@ -444,7 +421,7 @@ NotificationWindow::LoadSettings(bool startMonitor)
void void
NotificationWindow::LoadAppFilters(bool startMonitor) NotificationWindow::_LoadAppFilters(bool startMonitor)
{ {
BPath path; BPath path;
@ -491,7 +468,7 @@ NotificationWindow::LoadAppFilters(bool startMonitor)
void void
NotificationWindow::SaveAppFilters() NotificationWindow::_SaveAppFilters()
{ {
BPath path; BPath path;
@ -543,7 +520,6 @@ NotificationWindow::_LoadGeneralSettings(bool startMonitor)
views_t::iterator it; views_t::iterator it;
for (it = fViews.begin(); it != fViews.end(); ++it) { for (it = fViews.begin(); it != fViews.end(); ++it) {
NotificationView* view = (*it); NotificationView* view = (*it);
view->SetText(view->Application(), view->Title(), view->Text());
view->Invalidate(); view->Invalidate();
} }
@ -589,26 +565,10 @@ NotificationWindow::_LoadDisplaySettings(bool startMonitor)
else else
fIconSize = (icon_size)setting; fIconSize = (icon_size)setting;
if (settings.FindInt32(kLayoutName, &setting) != B_OK)
fLayout = kDefaultLayout;
else {
switch (setting) {
case 0:
fLayout = TitleAboveIcon;
break;
case 1:
fLayout = AllTextRightOfIcon;
break;
default:
fLayout = kDefaultLayout;
}
}
// Notify the view about the change // Notify the view about the change
views_t::iterator it; views_t::iterator it;
for (it = fViews.begin(); it != fViews.end(); ++it) { for (it = fViews.begin(); it != fViews.end(); ++it) {
NotificationView* view = (*it); NotificationView* view = (*it);
view->SetText(view->Application(), view->Title(), view->Text());
view->Invalidate(); view->Invalidate();
} }

View File

@ -26,8 +26,6 @@
class AppGroupView; class AppGroupView;
class AppUsage; class AppUsage;
class BorderView;
class SettingsFile;
typedef std::map<BString, AppGroupView*> appview_t; typedef std::map<BString, AppGroupView*> appview_t;
typedef std::map<BString, AppUsage*> appfilter_t; typedef std::map<BString, AppUsage*> appfilter_t;
@ -39,8 +37,6 @@ extern const float kCloseSize;
extern const float kExpandSize; extern const float kExpandSize;
extern const float kPenSize; extern const float kPenSize;
const uint32 kResizeToFit = 'IWrf';
class NotificationWindow : public BWindow { class NotificationWindow : public BWindow {
public: public:
NotificationWindow(); NotificationWindow();
@ -56,25 +52,22 @@ public:
icon_size IconSize(); icon_size IconSize();
int32 Timeout(); int32 Timeout();
infoview_layout Layout(); float Width();
float ViewWidth();
void ResizeAll(); void _ResizeAll();
private: private:
friend class AppGroupView; friend class AppGroupView;
void SetPosition(); void SetPosition();
void PopupAnimation(); void PopupAnimation();
void LoadSettings(bool startMonitor = false); void _LoadSettings(bool startMonitor = false);
void LoadAppFilters(bool startMonitor = false); void _LoadAppFilters(bool startMonitor = false);
void SaveAppFilters(); void _SaveAppFilters();
void _LoadGeneralSettings(bool startMonitor); void _LoadGeneralSettings(bool startMonitor);
void _LoadDisplaySettings(bool startMonitor); void _LoadDisplaySettings(bool startMonitor);
views_t fViews; views_t fViews;
BorderView* fBorder;
appview_t fAppViews; appview_t fAppViews;
BString fStatusText; BString fStatusText;
@ -83,7 +76,6 @@ private:
float fWidth; float fWidth;
icon_size fIconSize; icon_size fIconSize;
int32 fTimeout; int32 fTimeout;
infoview_layout fLayout;
appfilter_t fAppFilters; appfilter_t fAppFilters;
}; };