Ticket #1245: notifications1.patch

File notifications1.patch, 84.8 KB (added by plfiorini, 9 years ago)
  • headers/os/app/Notification.h

    diff --git a/headers/os/app/Notification.h b/headers/os/app/Notification.h
    index 22d61ab..d11e4b1 100644
    a b  
    66#define _NOTIFICATION_H
    77
    88
     9#include <Archivable.h>
    910#include <Entry.h>
    1011#include <List.h>
    1112#include <String.h>
    enum notification_type { 
    2223class BBitmap;
    2324
    2425
    25 class BNotification {
     26class BNotification : public BArchivable {
    2627public:
    2728                                BNotification(notification_type type);
    28                                 ~BNotification();
     29                                BNotification(BMessage* archive);
     30    virtual                     ~BNotification();
     31
     32            status_t            InitCheck() const;
     33
     34    static  BArchivable*        Instantiate(BMessage* archive);
     35    virtual status_t            Archive(BMessage* archive, bool deep = true) const;
    2936
    3037            notification_type   Type() const;
    3138
    32             const char*         Application() const;
    33             void                SetApplication(const BString& app);
     39            const char*         Group() const;
     40            void                SetGroup(const BString& group);
    3441
    3542            const char*         Title() const;
    3643            void                SetTitle(const BString& title);
    public: 
    6168            const BBitmap*      Icon() const;
    6269            status_t            SetIcon(const BBitmap* icon);
    6370
     71            status_t            Send(bigtime_t timeout = -1);
     72
    6473private:
     74            status_t            fInitStatus;
     75
    6576            notification_type   fType;
    66             BString             fAppName;
     77            BString             fGroup;
    6778            BString             fTitle;
    6879            BString             fContent;
    6980            BString             fID;
  • headers/os/app/Roster.h

    diff --git a/headers/os/app/Roster.h b/headers/os/app/Roster.h
    index e55e518..50a6612 100644
    a b  
    1313class BFile;
    1414class BMimeType;
    1515class BNodeInfo;
    16 class BNotification;
    1716
    1817
    1918struct app_info {
    class BRoster { 
    117116        void AddToRecentFolders(const entry_ref *folder,
    118117                    const char *appSig = 0) const;
    119118
    120         // notifications
    121         status_t Notify(const BNotification& notification,
    122                     bigtime_t timeout = -1) const;
    123 
    124119        // private/reserved stuff starts here
    125120        class Private;
    126121
  • headers/private/notification/AppUsage.h

    diff --git a/headers/private/notification/AppUsage.h b/headers/private/notification/AppUsage.h
    index c245c77..2c42961 100644
    a b  
    1919class BMessage;
    2020class NotificationReceived;
    2121
    22 typedef std::map<BString, NotificationReceived*> notify_t;
     22typedef std::map<BString, NotificationReceived*> notification_t;
    2323
    2424class AppUsage : public BFlattenable {
    2525public:
    2626                                        AppUsage();
    27                                         AppUsage(entry_ref ref, const char* name,
     27                                        AppUsage(const char* name,
    2828                                            bool allow = true);
    2929                                        ~AppUsage();
    3030
    public: 
    3636    virtual status_t                    Unflatten(type_code code, const void* buffer,
    3737                                            ssize_t numBytes);
    3838
    39             entry_ref                   Ref();
    4039            const char*                 Name();
    4140            bool                        Allowed(const char* title, notification_type type);
    4241            bool                        Allowed();
    public: 
    4544            void                        AddNotification(NotificationReceived* notification);
    4645
    4746private:
    48             entry_ref                   fRef;
    4947            BString                     fName;
    5048            bool                        fAllow;
    51             notify_t                    fNotifications;
     49            notification_t              fNotifications;
    5250};
    5351
    5452#endif  // _APP_USAGE_H
  • headers/private/notification/Notifications.h

    diff --git a/headers/private/notification/Notifications.h b/headers/private/notification/Notifications.h
    index 964b026..99a5dc4 100644
    a b  
    1212// Messages
    1313const uint32 kNotificationMessage       = 'nssm';
    1414
    15 // Notification layout
    16 enum infoview_layout {
    17     TitleAboveIcon = 0,
    18     AllTextRightOfIcon = 1
    19 };
    20 
    2115// Settings constants
    2216extern const char* kSettingsDirectory;
    2317extern const char* kFiltersSettings;
    extern const char* kLayoutName; 
    4034// Display default settings
    4135const float kDefaultWidth               = 300.0f;
    4236const icon_size kDefaultIconSize        = B_LARGE_ICON;
    43 const infoview_layout kDefaultLayout    = TitleAboveIcon;
    4437
    4538#endif  // _NOTIFICATIONS_H
  • src/bin/notify.cpp

    diff --git a/src/bin/notify.cpp b/src/bin/notify.cpp
    index 7ad9170..c2030b6 100644
    a b  
    1010
    1111#include <stdio.h>
    1212#include <stdlib.h>
    13 #include <string.h>
    1413
    1514#include <Application.h>
    1615#include <Bitmap.h>
     
    1918#include <Mime.h>
    2019#include <Notification.h>
    2120#include <Path.h>
    22 #include <Roster.h>
    2321#include <TranslationUtils.h>
    2422
    2523const char* kSignature          = "application/x-vnd.Haiku-notify";
    public: 
    5250private:
    5351            bool                fHasGoodArguments;
    5452            notification_type   fType;
    55             char*               fAppName;
    56             char*               fTitle;
    57             char*               fMsgId;
     53            BString             fGroup;
     54            BString             fTitle;
     55            BString             fMsgId;
    5856            float               fProgress;
    5957            bigtime_t           fTimeout;
    60             char*               fIconFile;
     58            BString             fIconFile;
    6159            entry_ref           fFileRef;
    62             char*               fMessage;
    63             char*               fApp;
     60            BString             fContent;
     61            BString             fOnClickApp;
    6462            bool                fHasFile;
    6563            entry_ref           fFile;
    6664            BList*              fRefs;
    NotifyApp::NotifyApp() 
    7674    BApplication(kSignature),
    7775    fHasGoodArguments(false),
    7876    fType(B_INFORMATION_NOTIFICATION),
    79     fAppName(NULL),
    80     fTitle(NULL),
    81     fMsgId(NULL),
    8277    fProgress(0.0f),
    83     fTimeout(0),
    84     fIconFile(NULL),
    85     fMessage(NULL),
    86     fApp(NULL),
     78    fTimeout(-1),
    8779    fHasFile(false)
    8880{
    8981    fRefs = new BList();
    NotifyApp::NotifyApp() 
    9385
    9486NotifyApp::~NotifyApp()
    9587{
    96     free(fAppName);
    97     free(fTitle);
    98     free(fMsgId);
    99     free(fIconFile);
    100     free(fMessage);
    101     free(fApp);
    102 
    10388    for (int32 i = 0; void* item = fRefs->ItemAt(i); i++)
    10489        delete (BEntry*)item;
    10590    delete fRefs;
    10691
    10792    for (int32 i = 0; void* item = fArgv->ItemAt(i); i++)
    108         free(item);
     93        delete (BString*)item;
    10994    delete fArgv;
    11095}
    11196
    NotifyApp::ArgvReceived(int32 argc, char** argv) 
    134119                    if (strncmp(kTypeNames[i], argument, strlen(argument)) == 0)
    135120                        fType = (notification_type)i;
    136121                }
    137             } else if (strcmp(option, "app") == 0)
    138                 fAppName = strdup(argument);
     122            } else if (strcmp(option, "group") == 0)
     123                fGroup = argument;
    139124            else if (strcmp(option, "title") == 0)
    140                 fTitle = strdup(argument);
     125                fTitle = argument;
    141126            else if (strcmp(option, "messageID") == 0)
    142                 fMsgId = strdup(argument);
     127                fMsgId = argument;
    143128            else if (strcmp(option, "progress") == 0)
    144129                fProgress = atof(argument);
    145130            else if (strcmp(option, "timeout") == 0)
    146131                fTimeout = atol(argument) * 1000000;
    147132            else if (strcmp(option, "icon") == 0) {
    148                 fIconFile = strdup(argument);
     133                fIconFile = argument;
    149134
    150                 if (get_ref_for_path(fIconFile, &fFileRef) < B_OK) {
     135                if (get_ref_for_path(fIconFile.String(), &fFileRef) < B_OK) {
    151136                    fprintf(stderr, "Bad icon path!\n\n");
    152137                    return;
    153138                }
    154139            } else if (strcmp(option, "onClickApp") == 0)
    155                 fApp = strdup(argument);
     140                fOnClickApp = argument;
    156141            else if (strcmp(option, "onClickFile") == 0) {
    157142                if (get_ref_for_path(argument, &fFile) != B_OK) {
    158143                    fprintf(stderr, "Bad path for --onClickFile!\n\n");
    NotifyApp::ArgvReceived(int32 argc, char** argv) 
    170155
    171156                fRefs->AddItem(new BEntry(&ref));
    172157            } else if (strcmp(option, "onClickArgv") == 0)
    173                 fArgv->AddItem(strdup(argument));
     158                fArgv->AddItem(new BString(argument));
    174159            else {
    175160                // Unrecognized option
    176161                fprintf(stderr, "Unrecognized option --%s\n\n", option);
    NotifyApp::ArgvReceived(int32 argc, char** argv) 
    188173        }
    189174    }
    190175
    191     // Check for missing arguments
    192     if (fAppName == NULL) {
    193         fprintf(stderr, "Missing --app argument!\n\n");
    194         return;
    195     }
    196     if (fTitle == NULL) {
    197         fprintf(stderr, "Missing --title argument!\n\n");
    198         return;
    199     }
    200 
    201     fMessage = strdup(argv[index]);
     176    fContent = argv[index];
    202177    fHasGoodArguments = true;
    203178}
    204179
    NotifyApp::_Usage() const 
    208183    fprintf(stderr, "Usage: notify [OPTION]... [MESSAGE]\n"
    209184        "Send notifications to notification_server.\n"
    210185        "  --type <type>\tNotification type,\n"
    211         "               \t      <type>: ");
     186        "               \t      <type> - \"information\" is assumed by default: ");
    212187
    213188    for (int32 i = 0; kTypeNames[i]; i++)
    214189        fprintf(stderr, kTypeNames[i + 1] ? "%s|" : "%s\n", kTypeNames[i]);
    215190
    216191    fprintf(stderr,
    217         "  --app <app name>\tApplication name\n"
     192        "  --group <group>\tGroup\n"
    218193        "  --title <title>\tMessage title\n"
    219194        "  --messageID <msg id>\tMessage ID\n"
    220195        "  --progress <float>\tProgress, value between 0.0 and 1.0  - if type is set to progress\n"
    NotifyApp::ReadyToRun() 
    256231{
    257232    if (HasGoodArguments()) {
    258233        BNotification notification(fType);
    259         notification.SetApplication(fAppName);
    260         notification.SetTitle(fTitle);
    261         notification.SetContent(fMessage);
    262 
    263         if (fMsgId != NULL)
     234        if (fGroup != "")
     235            notification.SetGroup(fGroup);
     236        if (fTitle != "")
     237            notification.SetTitle(fTitle);
     238        if (fContent != "")
     239            notification.SetContent(fContent);
     240
     241        if (fMsgId != "")
    264242            notification.SetMessageID(fMsgId);
    265243
    266244        if (fType == B_PROGRESS_NOTIFICATION)
    267245            notification.SetProgress(fProgress);
    268246
    269         if (fIconFile != NULL) {
     247        if (fIconFile != "") {
    270248            BBitmap* bitmap = _GetBitmap(&fFileRef);
    271249            if (bitmap) {
    272250                notification.SetIcon(bitmap);
    NotifyApp::ReadyToRun() 
    274252            }
    275253        }
    276254
    277         if (fApp != NULL)
    278             notification.SetOnClickApp(fApp);
     255        if (fOnClickApp != "")
     256            notification.SetOnClickApp(fOnClickApp);
    279257
    280258        if (fHasFile)
    281259            notification.SetOnClickFile(&fFile);
    NotifyApp::ReadyToRun() 
    289267        }
    290268
    291269        for (int32 i = 0; void* item = fArgv->ItemAt(i); i++) {
    292             const char* arg = (const char*)item;
    293             notification.AddOnClickArg(arg);
     270            BString* arg = (BString*)item;
     271            notification.AddOnClickArg(arg->String());
    294272        }
    295273
    296         status_t ret = be_roster->Notify(notification, fTimeout);
     274        status_t ret = notification.Send(fTimeout);
    297275        if (ret != B_OK) {
    298276            fprintf(stderr, "Failed to deliver notification: %s\n",
    299277                strerror(ret));
  • src/kits/app/Jamfile

    diff --git a/src/kits/app/Jamfile b/src/kits/app/Jamfile
    index cf85c79..d8008c1 100644
    a b if $(RUN_WITHOUT_APP_SERVER) != 0 { 
    1717    SubDirC++Flags $(defines) ;
    1818}
    1919
     20UseLibraryHeaders icon ;
    2021UsePrivateHeaders shared app interface kernel notification ;
    2122UsePrivateSystemHeaders ;
    2223
  • src/kits/app/Notification.cpp

    diff --git a/src/kits/app/Notification.cpp b/src/kits/app/Notification.cpp
    index 90c4f14..9d05f55 100644
    a b  
    44 *
    55 * Authors:
    66 *      Pier Luigi Fiorini, pierluigi.fiorini@gmail.com
    7  *      Stephan Aßmus <superstippi@gmx.de>
     7 *      Stephan Aßmus, superstippi@gmx.de
    88 */
    99
    1010
     
    1313#include <new>
    1414
    1515#include <stdlib.h>
    16 #include <string.h>
     16
     17#include <notification/Notifications.h>
    1718
    1819#include <Bitmap.h>
    1920#include <Message.h>
    2021
    2122
     23/*! \brief Creates a notification that's ready to be used.
     24
     25    \param type Notification type.
     26*/
    2227BNotification::BNotification(notification_type type)
    2328    :
     29    BArchivable(),
     30    fInitStatus(B_OK),
    2431    fType(type),
     32    fProgress(0.0f),
     33    fFile(NULL),
     34    fBitmap(NULL)
     35{
     36}
     37
     38
     39/*! \brief Creates a notification that's ready to be used.
     40
     41    \param archive Archived BNotification object.
     42*/
     43BNotification::BNotification(BMessage* archive)
     44    :
     45    BArchivable(archive),
     46    fInitStatus(B_OK),
     47    fProgress(0.0f),
    2548    fFile(NULL),
    2649    fBitmap(NULL)
    2750{
     51    int32 type;
     52    if (archive->FindInt32("_type", &type) == B_OK)
     53        fType = (notification_type)type;
     54    else
     55        fInitStatus = B_ERROR;
     56
     57    BString group;
     58    if (archive->FindString("_group", &group) == B_OK)
     59        SetGroup(group);
     60
     61    BString title;
     62    if (archive->FindString("_title", &title) == B_OK)
     63        SetTitle(title);
     64
     65    BString content;
     66    if (archive->FindString("_content", &content) == B_OK)
     67        SetContent(content);
     68
     69    BString messageID;
     70    if (archive->FindString("_messageID", &messageID) == B_OK)
     71        SetMessageID(messageID);
     72
     73    float progress;
     74    if (type == B_PROGRESS_NOTIFICATION
     75        && archive->FindFloat("_progress", &progress) == B_OK)
     76        SetProgress(progress);
     77
     78    BString onClickApp;
     79    if (archive->FindString("_onClickApp", &onClickApp) == B_OK)
     80        SetOnClickApp(onClickApp);
     81
     82    entry_ref onClickFile;
     83    if (archive->FindRef("_onClickFile", &onClickFile) == B_OK)
     84        SetOnClickFile(&onClickFile);
     85
     86    status_t ret = B_OK;
     87    BMessage icon;
     88    if ((ret = archive->FindMessage("_icon", &icon)) == B_OK) {
     89        BBitmap bitmap(&icon);
     90        ret = bitmap.InitCheck();
     91        if (ret == B_OK)
     92            ret = SetIcon(&bitmap);
     93    }
    2894}
    2995
    3096
     97/*! \brief Standard destructor.
     98 */
    3199BNotification::~BNotification()
    32100{
    33101    delete fFile;
    BNotification::~BNotification() 
    41109}
    42110
    43111
     112/*! \brief Returns initialization status.
     113 */
     114status_t
     115BNotification::InitCheck() const
     116{
     117    return fInitStatus;
     118}
     119
     120
     121/*! \brief Returns a new BNotification object from @archive.
     122
     123    Returns a new BNotification object, allocated by new and created
     124    with the version of the constructor that takes BMessage archive.
     125    However, if the message doesn't contain an archived data for a
     126    BNotification object, this method returns NULL.
     127
     128    \return BNotification object from @archive or NULL if it doesn't
     129            contain a valid BNotification object.
     130*/
     131BArchivable*
     132BNotification::Instantiate(BMessage* archive)
     133{
     134    if (validate_instantiation(archive, "BNotification"))
     135        return new(std::nothrow) BNotification(archive);
     136
     137    return NULL;
     138}
     139
     140
     141/*! \brief Archives the BNotification in the BMessages @archive.
     142
     143    \sa BArchivable::Archive(), Instantiate() static function.
     144    \return
     145    - \c B_OK: Everything went fine.
     146    - \c Other errors: Archiving has failed.
     147*/
     148status_t
     149BNotification::Archive(BMessage* archive, bool deep) const
     150{
     151    status_t status = BArchivable::Archive(archive, deep);
     152
     153    if (status == B_OK)
     154        status = archive->AddInt32("_type", (int32)fType);
     155
     156    if (status == B_OK && Group() != NULL)
     157        status = archive->AddString("_group", Group());
     158
     159    if (status == B_OK && Title() != NULL)
     160        status = archive->AddString("_title", Title());
     161
     162    if (status == B_OK && Content() != NULL)
     163        status = archive->AddString("_content", Content());
     164
     165    if (status == B_OK && MessageID() != NULL)
     166        status = archive->AddString("_messageID", MessageID());
     167
     168    if (status == B_OK && Type() == B_PROGRESS_NOTIFICATION)
     169        status = archive->AddFloat("_progress", Progress());
     170
     171    if (status == B_OK && OnClickApp() != NULL)
     172        status = archive->AddString("_onClickApp", OnClickApp());
     173
     174    if (status == B_OK && OnClickFile() != NULL)
     175        status = archive->AddRef("_onClickFile", OnClickFile());
     176
     177    if (status == B_OK) {
     178        for (int32 i = 0; i < CountOnClickRefs(); i++) {
     179            status = archive->AddRef("_onClickRef", OnClickRefAt(i));
     180            if (status != B_OK)
     181                break;
     182        }
     183    }
     184
     185    if (status == B_OK) {
     186        for (int32 i = 0; i < CountOnClickArgs(); i++) {
     187            status = archive->AddString("_onClickArgv", OnClickArgAt(i));
     188            if (status != B_OK)
     189                break;
     190        }
     191    }
     192
     193    if (status == B_OK) {
     194        const BBitmap* icon = Icon();
     195        if (icon != NULL) {
     196            BMessage iconArchive;
     197            status = icon->Archive(&iconArchive);
     198            if (status == B_OK)
     199                archive->AddMessage("_icon", &iconArchive);
     200        }
     201    }
     202
     203    return status;
     204}
     205
     206
     207/*! \brief Notification's type.
     208
     209    \return A value of the notification_type enum that represents
     210            notification type.
     211*/
    44212notification_type
    45213BNotification::Type() const
    46214{
    BNotification::Type() const 
    48216}
    49217
    50218
     219/*! \brief Returns notification's group.
     220
     221    \return Notification's group.
     222*/
    51223const char*
    52 BNotification::Application() const
     224BNotification::Group() const
    53225{
    54     return fAppName;
     226    if (fGroup == "")
     227        return NULL;
     228    return fGroup;
    55229}
    56230
    57231
     232/*! \brief Sets notification's group.
     233
     234    Notifications can be grouped together setting the same group.
     235*/
    58236void
    59 BNotification::SetApplication(const BString& app)
     237BNotification::SetGroup(const BString& group)
    60238{
    61     fAppName = app;
     239    fGroup = group;
    62240}
    63241
    64242
     243/*! \brief Returns notification's title.
     244
     245    \return Notification's title.
     246*/
    65247const char*
    66248BNotification::Title() const
    67249{
     250    if (fTitle == "")
     251        return NULL;
    68252    return fTitle;
    69253}
    70254
    71255
     256/*! \brief Set notification's title.
     257*/
    72258void
    73259BNotification::SetTitle(const BString& title)
    74260{
    BNotification::SetTitle(const BString& title) 
    76262}
    77263
    78264
     265/*! \brief Returns notification's message.
     266
     267    \return Notification's message.
     268*/
    79269const char*
    80270BNotification::Content() const
    81271{
     272    if (fContent == "")
     273        return NULL;
    82274    return fContent;
    83275}
    84276
    85277
     278/*! \brief Sets notification's message.
     279*/
    86280void
    87281BNotification::SetContent(const BString& content)
    88282{
    BNotification::SetContent(const BString& content) 
    90284}
    91285
    92286
     287/*! \brief Returns notification's message identifier.
     288
     289    \return Notification's message identifier.
     290*/
    93291const char*
    94292BNotification::MessageID() const
    95293{
     294    if (fID == "")
     295        return NULL;
    96296    return fID;
    97297}
    98298
    99299
     300/*! \brief Sets notification's message identifier.
     301*/
    100302void
    101303BNotification::SetMessageID(const BString& id)
    102304{
    BNotification::SetMessageID(const BString& id) 
    104306}
    105307
    106308
     309/*! \brief Returns progress information.
     310
     311    If notification's type is \c B_PROGRESS_NOTIFICATION, returns a value
     312    between 0.0 and 1.0 that represent progress percentage.
     313
     314    If notification's type is not \c B_PROGRESS_NOTIFICATION, returns -1.
     315
     316    \return Percentage if notification's type is B_PROGRESS_NOTIFICATION
     317            or otherwise -1.
     318*/
    107319float
    108320BNotification::Progress() const
    109321{
     322    if (fType != B_PROGRESS_NOTIFICATION)
     323        return -1;
    110324    return fProgress;
    111325}
    112326
    113327
     328/*! \brief Sets progress information.
     329
     330    Sets progress percentage, this information will be used only
     331    if notification's type is \c B_PROGRESS_NOTIFICATION.
     332
     333    The value of @progress must be between 0.0 and 1.0.
     334*/
    114335void
    115336BNotification::SetProgress(float progress)
    116337{
    117     fProgress = progress;
     338    if (progress < 0)
     339        fProgress = 0;
     340    else if (progress > 1)
     341        fProgress = 1;
     342    else
     343        fProgress = progress;
    118344}
    119345
    120346
    121347const char*
    122348BNotification::OnClickApp() const
    123349{
     350    if (fApp == "")
     351        return NULL;
    124352    return fApp;
    125353}
    126354
    BNotification::OnClickArgAt(int32 index) const 
    208436}
    209437
    210438
     439/*! \brief Notification's icon.
     440
     441    \return Notification's icon.
     442*/
    211443const BBitmap*
    212444BNotification::Icon() const
    213445{
    BNotification::Icon() const 
    215447}
    216448
    217449
     450/*! \brief Sets notification's icon.
     451
     452    Sets notification's icon.
     453    This method takes ownership of @icon.
     454
     455    \param icon Icon
     456    \return
     457    - \c B_OK: Everything went fine.
     458    - \c B_NO_MEMORY: Allocation of @icon copy has failed.
     459    - \c Other errors: Creation of @icon copy failed for some reason.
     460*/
    218461status_t
    219462BNotification::SetIcon(const BBitmap* icon)
    220463{
    BNotification::SetIcon(const BBitmap* icon) 
    230473    fBitmap = NULL;
    231474    return B_OK;
    232475}
     476
     477
     478/*! \brief Sends a notification to the notification_server.
     479
     480    The notification is delivered asynchronously to the notification_server,
     481    which will display it according to its settings and filters.
     482
     483    \param timeout Microseconds after the message fades out.
     484    \return
     485    - \c B_OK: Everything went fine.
     486    - \c B_BAD_PORT_ID: A connection to notification_server could not be
     487      established or the server is not up and running anymore.
     488    - \c Other errors: Building the message from the notification failed.
     489*/
     490status_t
     491BNotification::Send(bigtime_t timeout)
     492{
     493    BMessage msg(kNotificationMessage);
     494
     495    // Archive notification
     496    status_t ret = Archive(&msg);
     497
     498    // Custom time out
     499    if (ret == B_OK && timeout > 0)
     500        ret = msg.AddInt64("timeout", timeout);
     501
     502    // Send message
     503    if (ret == B_OK) {
     504        BMessenger server(kNotificationServerSignature);
     505        ret = server.SendMessage(&msg);
     506    }
     507
     508    return ret;
     509}
  • src/kits/app/Roster.cpp

    diff --git a/src/kits/app/Roster.cpp b/src/kits/app/Roster.cpp
    index 9e354cb..36390b8 100644
    a b  
    3636#include <Mime.h>
    3737#include <Node.h>
    3838#include <NodeInfo.h>
    39 #include <Notification.h>
    40 #include <notification/Notifications.h>
    4139#include <OS.h>
    4240#include <Path.h>
    4341#include <Query.h>
    BRoster::AddToRecentFolders(const entry_ref* folder, const char* appSig) const 
    16531651        DBG(OUT("WARNING: BRoster::AddToRecentDocuments() failed with error 0x%lx\n", err));
    16541652}
    16551653
    1656 /*! \brief Sends a notification to the notification_server.
    1657 
    1658     The notification is delivered asynchronously to the notification_server,
    1659     which will displays it according to its settings and filters.
    1660 
    1661     \param notification Notification message.
    1662     \param timeout Seconds after the message fades out.
    1663     \return
    1664     - \c B_OK: Everything went fine.
    1665     - \c B_BAD_PORT_ID: A connection to notification_server could not be
    1666       established or the server is not up and running anymore.
    1667     - \c Other errors: Building the message from the notification failed.
    1668 */
    1669 status_t
    1670 BRoster::Notify(const BNotification& notification, bigtime_t timeout) const
    1671 {
    1672     // TODO: Add BArchivable support to BNotification and use it here.
    1673     BMessage msg(kNotificationMessage);
    1674     status_t ret = msg.AddInt32("type", (int32)notification.Type());
    1675     if (ret == B_OK)
    1676         ret = msg.AddString("app", notification.Application());
    1677     if (ret == B_OK)
    1678         ret = msg.AddString("title", notification.Title());
    1679     if (ret == B_OK)
    1680         ret = msg.AddString("content", notification.Content());
    1681 
    1682     if (ret == B_OK && notification.MessageID() != NULL)
    1683         ret = msg.AddString("messageID", notification.MessageID());
    1684 
    1685     if (ret == B_OK && notification.Type() == B_PROGRESS_NOTIFICATION)
    1686         ret = msg.AddFloat("progress", notification.Progress());
    1687 
    1688     if (ret == B_OK && notification.OnClickApp() != NULL)
    1689         ret = msg.AddString("onClickApp", notification.OnClickApp());
    1690     if (ret == B_OK && notification.OnClickFile() != NULL)
    1691         ret = msg.AddRef("onClickFile", notification.OnClickFile());
    1692 
    1693     if (ret == B_OK) {
    1694         for (int32 i = 0; i < notification.CountOnClickRefs(); i++) {
    1695             ret = msg.AddRef("onClickRef", notification.OnClickRefAt(i));
    1696             if (ret != B_OK)
    1697                 break;
    1698         }
    1699     }
    1700 
    1701     if (ret == B_OK) {
    1702         for (int32 i = 0; i < notification.CountOnClickArgs(); i++) {
    1703             ret = msg.AddString("onClickArgv", notification.OnClickArgAt(i));
    1704             if (ret != B_OK)
    1705                 break;
    1706         }
    1707     }
    1708 
    1709     if (ret == B_OK) {
    1710         const BBitmap* icon = notification.Icon();
    1711         if (icon != NULL) {
    1712             BMessage archive;
    1713             ret = icon->Archive(&archive);
    1714             if (ret == B_OK)
    1715                 ret = msg.AddMessage("icon", &archive);
    1716         }
    1717     }
    1718 
    1719     // Custom time out
    1720     if (ret == B_OK && timeout > 0)
    1721         ret = msg.AddInt64("timeout", timeout);
    1722 
    1723     // Send message
    1724     if (ret == B_OK) {
    1725         BMessenger server(kNotificationServerSignature);
    1726         ret = server.SendMessage(&msg);
    1727     }
    1728 
    1729     return ret;
    1730 }
    1731 
    1732 
    17331654//  #pragma mark - Private or reserved
    17341655
    17351656
  • src/kits/notification/AppUsage.cpp

    diff --git a/src/kits/notification/AppUsage.cpp b/src/kits/notification/AppUsage.cpp
    index 7310796..2e1cb72 100644
    a b AppUsage::AppUsage() 
    2727}
    2828
    2929
    30 AppUsage::AppUsage(entry_ref ref, const char* name, bool allow)
     30AppUsage::AppUsage(const char* name, bool allow)
    3131    :
    32     fRef(ref),
    3332    fName(name),
    3433    fAllow(allow)
    3534{   
    AppUsage::AppUsage(entry_ref ref, const char* name, bool allow) 
    3837
    3938AppUsage::~AppUsage()
    4039{
    41     notify_t::iterator nIt;
     40    notification_t::iterator nIt;
    4241    for (nIt = fNotifications.begin(); nIt != fNotifications.end(); nIt++)
    4342        delete nIt->second;
    4443}
    status_t 
    5554AppUsage::Flatten(void* buffer, ssize_t numBytes) const
    5655{
    5756    BMessage msg;
    58     msg.AddString("app_name", fName);
    59     msg.AddRef("app_ref", &fRef);
    60     msg.AddBool("app_allow", fAllow);
     57    msg.AddString("signature", fName);
     58    msg.AddBool("allow", fAllow);
    6159
    62     notify_t::const_iterator nIt;
     60    notification_t::const_iterator nIt;
    6361    for (nIt = fNotifications.begin(); nIt != fNotifications.end(); nIt++)
    64         msg.AddFlat("notify", nIt->second);
     62        msg.AddFlat("notification", nIt->second);
    6563
    6664    if (numBytes < msg.FlattenedSize())
    6765        return B_ERROR;
    ssize_t 
    7472AppUsage::FlattenedSize() const
    7573{
    7674    BMessage msg;
    77     msg.AddString("app_name", fName);
    78     msg.AddRef("app_ref", &fRef);
    79     msg.AddBool("app_allow", fAllow);
     75    msg.AddString("signature", fName);
     76    msg.AddBool("allow", fAllow);
    8077
    81     notify_t::const_iterator nIt;
     78    notification_t::const_iterator nIt;
    8279    for (nIt = fNotifications.begin(); nIt != fNotifications.end(); nIt++)
    83         msg.AddFlat("notify", nIt->second);
     80        msg.AddFlat("notification", nIt->second);
    8481
    8582    return msg.FlattenedSize();
    8683}
    AppUsage::Unflatten(type_code code, const void* buffer, 
    113110    status = msg.Unflatten((const char*)buffer);
    114111
    115112    if (status == B_OK) {
    116         msg.FindString("app_name", &fName);
    117         msg.FindRef("app_ref", &fRef);
    118         msg.FindBool("app_allow", &fAllow);
     113        msg.FindString("signature", &fName);
     114        msg.FindBool("allow", &fAllow);
    119115
    120116        type_code type;
    121117        int32 count = 0;
    122118
    123         status = msg.GetInfo("notify", &type, &count);
     119        status = msg.GetInfo("notification", &type, &count);
    124120        if (status != B_OK)
    125121            return status;
    126122
    127123        for (int32 i = 0; i < count; i++) {
    128             NotificationReceived *notify = new NotificationReceived();
    129             msg.FindFlat("notify", i, notify);
    130             fNotifications[notify->Title()] = notify;
     124            NotificationReceived *notification = new NotificationReceived();
     125            msg.FindFlat("notification", i, notification);
     126            fNotifications[notification->Title()] = notification;
    131127        }
    132128
    133129        status = B_OK;
    AppUsage::Unflatten(type_code code, const void* buffer, 
    137133}
    138134
    139135                       
    140 entry_ref
    141 AppUsage::Ref()
    142 {
    143     return fRef;
    144 }
    145 
    146 
    147136const char*
    148137AppUsage::Name()
    149138{
    AppUsage::Allowed(const char* title, notification_type type) 
    157146    bool allowed = fAllow;
    158147
    159148    if (allowed) {
    160         notify_t::iterator nIt = fNotifications.find(title);
     149        notification_t::iterator nIt = fNotifications.find(title);
    161150        if (nIt == fNotifications.end()) {
    162151            allowed = true;     
    163152            fNotifications[title] = new NotificationReceived(title, type);
    AppUsage::Allowed() 
    182171NotificationReceived*
    183172AppUsage::NotificationAt(int32 index)
    184173{
    185     notify_t::iterator nIt = fNotifications.begin();
     174    notification_t::iterator nIt = fNotifications.begin();
    186175    for (int32 i = 0; i < index; i++)
    187176        nIt++;
    188177
  • src/kits/notification/Notifications.cpp

    diff --git a/src/kits/notification/Notifications.cpp b/src/kits/notification/Notifications.cpp
    index e386d74..cfc390f 100644
    a b  
    33 * Distributed under the terms of the MIT License.
    44 */
    55
    6 
    76#include <Notifications.h>
    87
    98
    const char* kTimeoutName = "timeout"; 
    2019// Display settings
    2120const char* kWidthName = "width";
    2221const char* kIconSizeName = "icon size";
    23 const char* kLayoutName = "layout";
    24 
  • src/preferences/notifications/DisplayView.cpp

    diff --git a/src/preferences/notifications/DisplayView.cpp b/src/preferences/notifications/DisplayView.cpp
    index fca5fca..f1fffbd 100644
    a b DisplayView::DisplayView(SettingsHost* host) 
    4949    fIconSize->SetLabelFromMarked(true);
    5050    fIconSizeField = new BMenuField(_T("Icon size:"), fIconSize);
    5151
    52     // Title position
    53     fTitlePosition = new BMenu("titlePosition");
    54     fTitlePosition->AddItem(new BMenuItem(_T("Above icon"),
    55         new BMessage(kSettingChanged)));
    56     fTitlePosition->AddItem(new BMenuItem(_T("Right of icon"),
    57         new BMessage(kSettingChanged)));
    58     fTitlePosition->SetLabelFromMarked(true);
    59     fTitlePositionField = new BMenuField(_T("Title position:"), fTitlePosition);
    60 
    6152    // Load settings
    6253    Load();
    6354
    DisplayView::DisplayView(SettingsHost* host) 
    7061        .Add(fWindowWidth->CreateTextViewLayoutItem(), 1, 0)
    7162        .Add(fIconSizeField->CreateLabelLayoutItem(), 0, 1)
    7263        .Add(fIconSizeField->CreateMenuBarLayoutItem(), 1, 1)
    73         .Add(fTitlePositionField->CreateLabelLayoutItem(), 0, 2)
    74         .Add(fTitlePositionField->CreateMenuBarLayoutItem(), 1, 2)
    75         .Add(BSpaceLayoutItem::CreateGlue(), 0, 3, 2, 1)
     64        .Add(BSpaceLayoutItem::CreateGlue(), 0, 2, 2, 1)
    7665    );
    7766}
    7867
    DisplayView::AttachedToWindow() 
    8271{
    8372    fWindowWidth->SetTarget(this);
    8473    fIconSize->SetTargetForItems(this);
    85     fTitlePosition->SetTargetForItems(this);
    8674}
    8775
    8876
    DisplayView::Load() 
    146134    if (item)
    147135        item->SetMarked(true);
    148136
    149     infoview_layout layout;
    150     if (settings.FindInt32(kLayoutName, &setting) != B_OK)
    151         layout = kDefaultLayout;
    152     else {
    153         switch (setting) {
    154             case 0:
    155                 layout = TitleAboveIcon;
    156                 break;
    157             case 1:
    158                 layout = AllTextRightOfIcon;
    159                 break;
    160             default:
    161                 layout = kDefaultLayout;
    162         }
    163     }
    164     item = fTitlePosition->ItemAt(layout);
    165     if (item)
    166         item->SetMarked(true);
    167 
    168137    return B_OK;
    169138}
    170139
    DisplayView::Save() 
    195164    }
    196165    settings.AddInt32(kIconSizeName, (int32)iconSize);
    197166
    198     int32 layout = fTitlePosition->IndexOf(fTitlePosition->FindMarked());
    199     if (layout == B_ERROR)
    200         layout = (int32)kDefaultLayout;
    201     settings.AddInt32(kLayoutName, layout);
    202 
    203167    // Save settings file
    204168    BFile file(path.Path(), B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
    205169    status_t ret = settings.Flatten(&file);
  • src/preferences/notifications/DisplayView.h

    diff --git a/src/preferences/notifications/DisplayView.h b/src/preferences/notifications/DisplayView.h
    index ddf528c..8c0ebe1 100644
    a b private: 
    2828            BTextControl*   fWindowWidth;
    2929            BMenu*          fIconSize;
    3030            BMenuField*     fIconSizeField;
    31             BMenu*          fTitlePosition;
    32             BMenuField*     fTitlePositionField;
    3331
    3432};
    3533
  • src/servers/notification/AppGroupView.cpp

    diff --git a/src/servers/notification/AppGroupView.cpp b/src/servers/notification/AppGroupView.cpp
    index 9612f54..114f392 100644
    a b  
    1313
    1414#include <algorithm>
    1515
     16#include <GroupLayout.h>
     17#include <GroupView.h>
     18
    1619#include "AppGroupView.h"
    1720
    1821#include "NotificationWindow.h"
     
    2124
    2225AppGroupView::AppGroupView(NotificationWindow* win, const char* label)
    2326    :
    24     BView(BRect(0, 0, win->ViewWidth(), 1), label, B_FOLLOW_LEFT_RIGHT,
    25         B_WILL_DRAW|B_FULL_UPDATE_ON_RESIZE|B_FRAME_EVENTS),
     27    BBox(B_FANCY_BORDER, (fView = new BGroupView(B_VERTICAL, 10))),
    2628    fLabel(label),
    2729    fParent(win),
    2830    fCollapsed(false)
    2931{
    30     Show();
     32    // If no group was specified we don't have any border or label
     33    if (label == NULL)
     34        SetBorder(B_NO_BORDER);
     35    else
     36        SetLabel(label);
    3137}
    3238
    3339
    AppGroupView::~AppGroupView() 
    3743
    3844
    3945void
    40 AppGroupView::AttachedToWindow()
    41 {
    42     SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
    43     SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
    44     SetHighColor(ui_color(B_PANEL_TEXT_COLOR));
    45 }
    46 
    47 
    48 void
    49 AppGroupView::Draw(BRect updateRect)
    50 {
    51     FillRect(Bounds(), B_SOLID_LOW);
    52 
    53     BString label = fLabel;
    54     if (fCollapsed)
    55         label << " (" << fInfo.size() << ")";
    56 
    57     font_height fh;
    58     be_bold_font->GetHeight(&fh);
    59     float labelOffset = fh.ascent + fh.leading;
    60 
    61     BRect borderRect = Bounds().InsetByCopy(kEdgePadding, kEdgePadding);
    62     borderRect.top = labelOffset;
    63 
    64     BRect textRect = borderRect;
    65     textRect.left = kEdgePadding * 2;
    66     textRect.right = textRect.left + be_bold_font->StringWidth(label.String())
    67         + (kEdgePadding * 3);
    68     textRect.bottom = labelOffset;
    69 
    70     BRect closeCross = fCloseRect;
    71     closeCross.InsetBy(kSmallPadding, kSmallPadding);
    72 
    73     rgb_color detailCol = ui_color(B_CONTROL_BORDER_COLOR);
    74     detailCol = tint_color(detailCol, B_LIGHTEN_2_TINT);
    75     // detailCol = tint_color(detailCol, B_LIGHTEN_1_TINT);
    76 
    77     if (fCollapsed) {
    78         PushState();
    79             SetFont(be_bold_font);
    80             SetPenSize(kPenSize);
    81             float linePos = textRect.top + textRect.Height() / 2;
    82 
    83             // Draw the line to the expand widget           
    84             PushState();
    85                 SetHighColor(detailCol);               
    86                 StrokeLine(BPoint(kEdgePadding, linePos), BPoint(fCollapseRect.left, linePos));
    87             PopState();
    88            
    89             // Draw the expand widget
    90             PushState();
    91                 SetHighColor(detailCol);
    92                 StrokeRoundRect(fCollapseRect, kSmallPadding, kSmallPadding);
    93                
    94                 BPoint expandHorStart(fCollapseRect.left + kSmallPadding, fCollapseRect.Height() / 2 + fCollapseRect.top);
    95                 BPoint expandHorEnd(fCollapseRect.right - kSmallPadding, fCollapseRect.Height() / 2 + fCollapseRect.top);           
    96                 StrokeLine(expandHorStart, expandHorEnd);
    97                
    98                 BPoint expandVerStart(fCollapseRect.Width() / 2 + fCollapseRect.left, fCollapseRect.top + kSmallPadding);
    99                 BPoint expandVerEnd(fCollapseRect.Width() / 2 + fCollapseRect.left, fCollapseRect.bottom - kSmallPadding);             
    100                 StrokeLine(expandVerStart, expandVerEnd);
    101             PopState();
    102            
    103             // Draw the app title
    104             DrawString(label.String(), BPoint(fCollapseRect.right + kEdgePadding, labelOffset + kEdgePadding));
    105            
    106             // Draw the line from the label to the close widget
    107             PushState();
    108                 SetHighColor(detailCol);
    109                
    110                 BPoint lineSeg2Start(textRect.right + kSmallPadding / 2, linePos);
    111                 BPoint lineSeg2End(fCloseRect.left, linePos);
    112                 StrokeLine(lineSeg2Start, lineSeg2End);
    113             PopState();
    114 
    115             // Draw the dismiss widget
    116             PushState();
    117                 SetHighColor(detailCol);
    118 
    119                 StrokeRoundRect(fCloseRect, kSmallPadding, kSmallPadding);
    120 
    121                 StrokeLine(closeCross.LeftTop(), closeCross.RightBottom());
    122                 StrokeLine(closeCross.RightTop(), closeCross.LeftBottom());
    123             PopState();
    124 
    125             // Draw the line from the dismiss widget
    126             PushState();
    127                 SetHighColor(detailCol);
    128 
    129                 BPoint lineSeg3Start(fCloseRect.right, linePos);
    130                 BPoint lineSeg3End(borderRect.right, linePos);
    131                 StrokeLine(lineSeg3Start, lineSeg3End);
    132             PopState();
    133 
    134         PopState();
    135     } else {
    136         PushState();
    137             SetFont(be_bold_font);
    138             SetPenSize(kPenSize);
    139 
    140             // Draw the border
    141             PushState();
    142                 SetHighColor(detailCol);
    143                 // StrokeRoundRect(borderRect, kEdgePadding, kEdgePadding * 2);
    144                 StrokeRect(borderRect);
    145             PopState();
    146 
    147             FillRect(textRect, B_SOLID_LOW);
    148 
    149             // Draw the collapse widget
    150             PushState();
    151                 SetHighColor(detailCol);
    152                 StrokeRoundRect(fCollapseRect, kSmallPadding, kSmallPadding);
    153 
    154                 BPoint expandHorStart(fCollapseRect.left + kSmallPadding, fCollapseRect.Height() / 2 + fCollapseRect.top);
    155                 BPoint expandHorEnd(fCollapseRect.right - kSmallPadding, fCollapseRect.Height() / 2 + fCollapseRect.top);
    156 
    157                 StrokeLine(expandHorStart, expandHorEnd);
    158             PopState();
    159 
    160             // Draw the dismiss widget
    161             PushState();
    162                 SetHighColor(detailCol);           
    163                 FillRect(fCloseRect, B_SOLID_LOW);
    164 
    165                 StrokeRoundRect(fCloseRect, kSmallPadding, kSmallPadding);
    166 
    167                 StrokeLine(closeCross.LeftTop(), closeCross.RightBottom());
    168                 StrokeLine(closeCross.RightTop(), closeCross.LeftBottom());
    169             PopState();
    170 
    171             // Draw the label
    172             DrawString(label.String(), BPoint(fCollapseRect.right + kEdgePadding, labelOffset + kEdgePadding));
    173         PopState();
    174     }
    175 
    176     Sync();
    177 }
    178 
    179 
    180 void
    18146AppGroupView::MouseDown(BPoint point)
    18247{
    18348    bool changed = false;
     49
     50    // User is closing all the children
    18451    if (fCloseRect.Contains(point)) {
    18552        changed = true;
    18653
    18754        int32 children = fInfo.size();
     55
    18856        for (int32 i = 0; i < children; i++) {
    189             fInfo[i]->RemoveSelf();
     57            fView->GetLayout()->RemoveView(fInfo[i]);
    19058            delete fInfo[i];
    19159        }
     60
    19261        fInfo.clear();
    19362    }
    19463
     64    // User is collapsing this group box
    19565    if (fCollapseRect.Contains(point)) {
    19666        fCollapsed = !fCollapsed;
    19767        changed = true;
    19868    }
    19969
    200     if (changed) {
    201         ResizeViews();
    202         Invalidate();
    203     }
    204 }
    205 
    206 
    207 void
    208 AppGroupView::GetPreferredSize(float* width, float* height)
    209 {
    210     font_height fh;
    211     be_bold_font->GetHeight(&fh);
    212 
    213     float h = fh.ascent + fh.leading + fh.leading;
    214     h += kEdgePadding * 2; // Padding between top and bottom of label
    215 
    216     if (!fCollapsed) {
    217         int32 children = fInfo.size();
    218 
    219         for (int32 i = 0; i < children; i++) {
    220             float childHeight = 0;
    221             float childWidth = 0;
    222            
    223             fInfo[i]->GetPreferredSize(&childWidth, &childHeight);
    224            
    225             h += childHeight;
    226         }
    227     }
    228 
    229     h += kEdgePadding;
    230 
    231     *width = fParent->ViewWidth();
    232     *height = h;
     70    if (changed)
     71        _ResizeViews();
    23372}
    23473
    23574
    AppGroupView::MessageReceived(BMessage* msg) 
    24786
    24887            if (vIt != fInfo.end()) {
    24988                fInfo.erase(vIt);
    250                 view->RemoveSelf();
     89                fView->GetLayout()->RemoveView(view);
    25190                delete view;
    25291            }
    25392
    254             ResizeViews();
    255             Invalidate();
     93            if (Window() != NULL)
     94                Window()->PostMessage(msg);
    25695
    257             // When all the views are destroy, save app filters
    258             if (fInfo.size() == 0)
    259                 dynamic_cast<NotificationWindow*>(Window())->SaveAppFilters();
     96            _ResizeViews();
    26097            break;
    26198        }
    26299        default:
    AppGroupView::MessageReceived(BMessage* msg) 
    265102}
    266103
    267104
     105bool
     106AppGroupView::HasChildren()
     107{
     108    return !fInfo.empty();
     109}
     110
     111
    268112void
    269113AppGroupView::AddInfo(NotificationView* view)
    270114{
    271115    BString id = view->MessageID();
     116    bool found = false;
     117
    272118    if (id.Length() > 0) {
    273119        int32 children = fInfo.size();
    274         bool found = false;
    275120
    276121        for (int32 i = 0; i < children; i++) {
    277             if (fInfo[i]->HasMessageID(id.String())) {
    278                 fInfo[i]->RemoveSelf();
     122            // Replace a child with the same message identifier
     123            if (id == fInfo[i]->MessageID()) {
     124                fView->GetLayout()->RemoveView(fInfo[i]);
    279125                delete fInfo[i];
    280                
     126
    281127                fInfo[i] = view;
    282128                found = true;
    283                
    284129                break;
    285130            }
    286131        }
     132    }
    287133
    288         if (!found)
    289             fInfo.push_back(view);
    290     } else
     134    // Add child to the list if it's a new one
     135    if (!found)
    291136        fInfo.push_back(view);
    292137
     138#if 0
    293139    if (fParent->IsHidden())
    294140        fParent->Show();
     141#endif
     142
     143    // Add the new child
     144    fView->GetLayout()->AddView(view);
     145
     146    // Show this group and child if hidden
    295147    if (IsHidden())
    296148        Show();
    297149    if (view->IsHidden())
    298150        view->Show();
    299151
    300     AddChild(view);
    301 
    302     ResizeViews();
    303     Invalidate();
     152    _ResizeViews();
    304153}
    305154
    306155
    307156void
    308 AppGroupView::ResizeViews()
     157AppGroupView::_ResizeViews()
    309158{
    310     font_height fh;
    311     be_bold_font->GetHeight(&fh);
    312 
    313     float offset = fh.ascent + fh.leading + fh.descent;
    314159    int32 children = fInfo.size();
    315160
    316161    if (!fCollapsed) {
    317         offset += kEdgePadding + kPenSize;
    318 
    319162        for (int32 i = 0; i < children; i++) {
    320             fInfo[i]->ResizeToPreferred();
    321             fInfo[i]->MoveTo(kEdgePadding + kPenSize, offset);
    322            
    323             offset += fInfo[i]->Bounds().Height();
    324163            if (fInfo[i]->IsHidden())
    325164                fInfo[i]->Show();
    326             fInfo[i]->SetPosition(false, false);
    327         };
     165        }
    328166    } else {
    329167        for (int32 i = 0; i < children; i++)
    330168            if (!fInfo[i]->IsHidden())
    331169                fInfo[i]->Hide();
    332170    }
    333171
    334     if (children == 1)
    335         fInfo[0]->SetPosition(true, true);
    336     else if (children > 1) {
    337         fInfo[0]->SetPosition(true, false);
    338         fInfo[children - 1]->SetPosition(false, true);
    339     }
    340 
    341     ResizeTo(fParent->ViewWidth(), offset);
     172#if 0
    342173    float labelOffset = fh.ascent + fh.leading;
    343174
    344175    BRect borderRect = Bounds().InsetByCopy(kEdgePadding, kEdgePadding);
    AppGroupView::ResizeViews() 
    354185    fCloseRect.left = fCloseRect.right - kCloseSize;
    355186    fCloseRect.bottom = fCloseRect.top + kCloseSize;
    356187    fCloseRect.OffsetTo(fCloseRect.left, kEdgePadding * 1.5);
    357 
    358     fParent->ResizeAll();
    359 }
    360 
    361 
    362 bool
    363 AppGroupView::HasChildren()
    364 {
    365     return !fInfo.empty();
     188#endif
    366189}
  • src/servers/notification/AppGroupView.h

    diff --git a/src/servers/notification/AppGroupView.h b/src/servers/notification/AppGroupView.h
    index eeb9a81..d0ec478 100644
    a b  
    11/*
    2  * Copyright 2005-2008, Mikael Eiman.
    3  * Copyright 2005-2008, Michael Davidson.
     2 * Copyright 2010, Haiku, Inc. All Rights Reserved.
     3 * Copyright 2008-2009, Pier Luigi Fiorini. All Rights Reserved.
     4 * Copyright 2004-2008, Michael Davidson. All Rights Reserved.
     5 * Copyright 2004-2007, Mikael Eiman. All Rights Reserved.
    46 * Distributed under the terms of the MIT License.
    5  *
    6  * Authors:
    7  *              Mikael Eiman <mikael@eiman.tv>
    8  *              Michael Davidson <slaad@bong.com.au>
    97 */
    10 
    11 #ifndef APPGROUPVIEW_H
    12 #define APPGROUPVIEW_H
     8#ifndef _APP_GROUP_VIEW_H
     9#define _APP_GROUP_VIEW_H
    1310
    1411#include <vector>
    1512
     13#include <Box.h>
    1614#include <String.h>
    17 #include <View.h>
     15
     16class BGroupView;
    1817
    1918class NotificationWindow;
    2019class NotificationView;
    2120
    22 typedef std::vector<NotificationView *> infoview_t;
    23 
    24 class AppGroupView : public BView {
    25     public:
    26                             AppGroupView(NotificationWindow *win, const char *label);
    27                             ~AppGroupView(void);
    28    
    29         // Hooks
    30         void                AttachedToWindow(void);
    31         void                Draw(BRect bounds);
    32         void                MouseDown(BPoint point);
    33         void                GetPreferredSize(float *width, float *height);
    34         void                MessageReceived(BMessage *msg);
    35    
    36         // Public
    37         void                AddInfo(NotificationView *view);
    38         void                ResizeViews(void);
    39         bool                HasChildren(void);
    40    
    41     private:
    42         BString             fLabel;
    43         NotificationWindow          *fParent;
    44         infoview_t          fInfo;
    45         bool                fCollapsed;
    46         BRect               fCloseRect;
    47         BRect               fCollapseRect;
     21typedef std::vector<NotificationView*> infoview_t;
     22
     23class AppGroupView : public BBox {
     24public:
     25                                AppGroupView(NotificationWindow* win, const char* label);
     26                                ~AppGroupView();
     27
     28    virtual void                MouseDown(BPoint point);
     29    virtual void                MessageReceived(BMessage* msg);
     30
     31            bool                HasChildren();
     32
     33            void                AddInfo(NotificationView* view);
     34
     35private:
     36            void                _ResizeViews();
     37
     38            BString             fLabel;
     39            NotificationWindow* fParent;
     40            BGroupView*         fView;
     41            infoview_t          fInfo;
     42            bool                fCollapsed;
     43            BRect               fCloseRect;
     44            BRect               fCollapseRect;
    4845};
    4946
    50 #endif
     47#endif  // _APP_GROUP_VIEW_H
  • src/servers/notification/Jamfile

    diff --git a/src/servers/notification/Jamfile b/src/servers/notification/Jamfile
    index 26d0652..5babfb4 100644
    a b  
    11SubDir HAIKU_TOP src servers notification ;
    22
    33UsePrivateHeaders notification ;
    4 UseLibraryHeaders icon ;
    54
    65Server notification_server :
    76    AppGroupView.cpp
    8     BorderView.cpp
    97    NotificationServer.cpp
    108    NotificationView.cpp
    119    NotificationWindow.cpp
    12     : be $(TARGET_LIBSTDC++) libicon.a libnotification.a
     10    : be translation $(TARGET_LIBSTDC++) libnotification.a
    1311    : notification_server.rdef
    1412;
    1513
    16 Depends notification_server : libicon.a ;
    1714Depends notification_server : libnotification.a ;
  • src/servers/notification/NotificationServer.cpp

    diff --git a/src/servers/notification/NotificationServer.cpp b/src/servers/notification/NotificationServer.cpp
    index bd874e3..0b528c2 100644
    a b const char* kSoundNames[] = { 
    2424NotificationServer::NotificationServer()
    2525    : BApplication(kNotificationServerSignature)
    2626{
    27     fWindow = new NotificationWindow();
    2827}
    2928
    3029
    NotificationServer::~NotificationServer() 
    3433
    3534
    3635void
     36NotificationServer::ReadyToRun()
     37{
     38    fWindow = new NotificationWindow();
     39}
     40
     41
     42void
    3743NotificationServer::MessageReceived(BMessage* message)
    3844{
    3945    switch (message->what) {
    NotificationServer::MessageReceived(BMessage* message) 
    6167}
    6268
    6369
    64 bool
    65 NotificationServer::QuitRequested()
    66 {
    67     if (fWindow && fWindow->Lock()) {
    68         fWindow->Quit();
    69         fWindow = NULL;
    70     }
    71     return true;
    72 }
    73 
    74 
    7570status_t
    7671NotificationServer::GetSupportedSuites(BMessage* msg)
    7772{
    main(int argc, char* argv[]) 
    110105        add_system_beep_event(kSoundNames[i++], 0);
    111106
    112107    // Start!
    113     NotificationServer* server = new NotificationServer();
    114     server->Run();
     108    NotificationServer server;
     109    server.Run();
    115110
    116111    return 0;
    117112}
  • src/servers/notification/NotificationServer.h

    diff --git a/src/servers/notification/NotificationServer.h b/src/servers/notification/NotificationServer.h
    index aff0da1..7a504fb 100644
    a b public: 
    1414                            NotificationServer();
    1515    virtual                 ~NotificationServer();
    1616
     17    virtual void            ReadyToRun();
    1718    virtual void            MessageReceived(BMessage* message);
    18     virtual bool            QuitRequested();
    1919
    2020    virtual status_t        GetSupportedSuites(BMessage* msg);
    2121    virtual BHandler*       ResolveSpecifier(BMessage* msg, int32 index, BMessage* spec,
  • src/servers/notification/NotificationView.cpp

    diff --git a/src/servers/notification/NotificationView.cpp b/src/servers/notification/NotificationView.cpp
    index f5671f1..2e4ba93 100644
    a b  
    99 *      Michael Davidson, slaad@bong.com.au
    1010 *      Mikael Eiman, mikael@eiman.tv
    1111 *      Pier Luigi Fiorini, pierluigi.fiorini@gmail.com
    12  *      Stephan Aßmus <superstippi@gmx.de>
     12 *      Stephan Aßmus, superstippi@gmx.de
    1313 */
    1414
    15 #include <stdlib.h>
    16 
    17 #include <Font.h>
    18 #include <IconUtils.h>
     15#include <ControlLook.h>
     16#include <LayoutUtils.h>
    1917#include <Messenger.h>
    20 #include <Picture.h>
    21 #include <PropertyInfo.h>
    22 #include <Region.h>
    23 #include <Resources.h>
     18#include <Path.h>
    2419#include <Roster.h>
    25 #include <StringView.h>
    26 #include <TranslationUtils.h>
    2720
    2821#include "NotificationView.h"
    2922#include "NotificationWindow.h"
    3023
    31 const char* kSmallIconAttribute = "BEOS:M:STD_ICON";
    32 const char* kLargeIconAttribute = "BEOS:L:STD_ICON";
    33 const char* kIconAttribute      = "BEOS:ICON";
    34 
    3524property_info message_prop_list[] = {
    36     { "type", {B_GET_PROPERTY, B_SET_PROPERTY, 0},
    37         {B_DIRECT_SPECIFIER, 0}, "get the notification type"},
    38     { "app", {B_GET_PROPERTY, B_SET_PROPERTY, 0},
    39         {B_DIRECT_SPECIFIER, 0}, "get notification's app"},
    40     { "title", {B_GET_PROPERTY, B_SET_PROPERTY, 0},
    41         {B_DIRECT_SPECIFIER, 0}, "get notification's title"},
    42     { "content", {B_GET_PROPERTY, B_SET_PROPERTY, 0},
    43         {B_DIRECT_SPECIFIER, 0}, "get notification's contents"},
    44     { "icon", {B_GET_PROPERTY, 0},
    45         {B_DIRECT_SPECIFIER, 0}, "get icon as an archived bitmap"},
    46     { "progress", {B_GET_PROPERTY, B_SET_PROPERTY, 0},
    47         {B_DIRECT_SPECIFIER, 0}, "get the progress (between 0.0 and 1.0)"},
    48     { NULL }
     25    {
     26        "type",
     27        { B_GET_PROPERTY, B_SET_PROPERTY, 0 },
     28        { B_DIRECT_SPECIFIER, 0 },
     29        "get the notification type"
     30    },
     31    {
     32        "group",
     33        { B_GET_PROPERTY, B_SET_PROPERTY, 0 },
     34        { B_DIRECT_SPECIFIER, 0 },
     35        "get notification's group"
     36    },
     37    {
     38        "title",
     39        { B_GET_PROPERTY, B_SET_PROPERTY, 0 },
     40        { B_DIRECT_SPECIFIER, 0 },
     41        "get notification's title"
     42    },
     43    {
     44        "content",
     45        { B_GET_PROPERTY, B_SET_PROPERTY, 0 },
     46        { B_DIRECT_SPECIFIER, 0 },
     47        "get notification's contents"
     48    },
     49    {
     50        "icon",
     51        { B_GET_PROPERTY, 0 },
     52        { B_DIRECT_SPECIFIER, 0 },
     53        "get icon as an archived bitmap"
     54    },
     55    {
     56        "progress",
     57        { B_GET_PROPERTY, B_SET_PROPERTY, 0 },
     58        { B_DIRECT_SPECIFIER, 0 },
     59        "get the progress (between 0.0 and 1.0)"
     60    },
     61    { 0, { 0 }, { 0 }, 0 }
    4962};
    5063
    5164
    5265NotificationView::NotificationView(NotificationWindow* win,
    53     notification_type type, const char* app, const char* title, const char* text,
    54     BMessage* details)
     66    BNotification* notification, bigtime_t timeout)
    5567    :
    56     BView(BRect(0, 0, win->ViewWidth(), 1), "NotificationView",
    57         B_FOLLOW_LEFT_RIGHT, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE
     68    BView("NotificationView", B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE
    5869        | B_FRAME_EVENTS),
    5970    fParent(win),
    60     fType(type),
     71    fNotification(notification),
     72    fTimeout(timeout),
    6173    fRunner(NULL),
    62     fProgress(0.0f),
    63     fMessageID(""),
    64     fDetails(details),
    65     fBitmap(NULL),
    66     fIsFirst(false),
    67     fIsLast(false)
     74    fBitmap(NULL)
    6875{
    69     BMessage iconMsg;
    70     if (fDetails->FindMessage("icon", &iconMsg) == B_OK)
    71         fBitmap = new BBitmap(&iconMsg);
    72 
    73     if (!fBitmap)
    74         _LoadIcon();
    75 
    76     const char* messageID = NULL;
    77     if (fDetails->FindString("messageID", &messageID) == B_OK)
    78         fMessageID = messageID;
     76    if (fNotification->Icon() != NULL)
     77        fBitmap = new BBitmap(fNotification->Icon());
    7978
    80     if (fDetails->FindFloat("progress", &fProgress) != B_OK)
    81         fProgress = 0.0f;
     79    if (fTimeout <= 0)
     80        fTimeout = fParent->Timeout() * 1000000;
    8281
    83     // Progress is between 0 and 1
    84     if (fProgress < 0.0f)
    85         fProgress = 0.0f;
    86     if (fProgress > 1.0f)
    87         fProgress = 1.0f;
     82    SetText();
    8883
    89     SetText(app, title, text);
    90     ResizeToPreferred();
    91 
    92     switch (type) {
     84    switch (fNotification->Type()) {
    9385        case B_IMPORTANT_NOTIFICATION:
    9486            SetViewColor(255, 255, 255);
    9587            SetLowColor(255, 255, 255);
    NotificationView::NotificationView(NotificationWindow* win, 
    10193        default:
    10294            SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
    10395            SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
    104             break;
    10596    }
    10697}
    10798
    NotificationView::NotificationView(NotificationWindow* win, 
    109100NotificationView::~NotificationView()
    110101{
    111102    delete fRunner;
    112     delete fDetails;
    113103    delete fBitmap;
     104    delete fNotification;
    114105
    115106    LineInfoList::iterator lIt;
    116107    for (lIt = fLines.begin(); lIt != fLines.end(); lIt++)
    NotificationView::AttachedToWindow() 
    123114{
    124115    BMessage msg(kRemoveView);
    125116    msg.AddPointer("view", this);
    126     bigtime_t timeout = -1;
    127117
    128     if (fDetails->FindInt64("timeout", &timeout) != B_OK)
    129         timeout = fParent->Timeout() * 1000000;
    130 
    131     if (timeout > 0)
    132         fRunner = new BMessageRunner(BMessenger(Parent()), &msg, timeout, 1);
     118    fRunner = new BMessageRunner(BMessenger(Parent()), &msg, fTimeout, 1);
    133119}
    134120
    135121
    NotificationView::MessageReceived(BMessage* msg) 
    151137
    152138            if (msgOkay) {
    153139                if (strcmp(property, "type") == 0)
    154                     reply.AddInt32("result", fType);
     140                    reply.AddInt32("result", fNotification->Type());
    155141
    156                 if (strcmp(property, "app") == 0)
    157                     reply.AddString("result", fApp);
     142                if (strcmp(property, "group") == 0)
     143                    reply.AddString("result", fNotification->Group());
    158144
    159145                if (strcmp(property, "title") == 0)
    160                     reply.AddString("result", fTitle);
     146                    reply.AddString("result", fNotification->Title());
    161147
    162148                if (strcmp(property, "content") == 0)
    163                     reply.AddString("result", fText);
     149                    reply.AddString("result", fNotification->Content());
    164150
    165151                if (strcmp(property, "progress") == 0)
    166                     reply.AddFloat("result", fProgress);
     152                    reply.AddFloat("result", fNotification->Progress());
    167153
    168154                if ((strcmp(property, "icon") == 0) && fBitmap) {
    169155                    BMessage archive;
    NotificationView::MessageReceived(BMessage* msg) 
    193179                msgOkay = false;
    194180
    195181            if (msgOkay) {
    196                 if (strcmp(property, "app") == 0)
    197                     msg->FindString("data", &fApp);
     182                const char* value = NULL;
     183
     184                if (strcmp(property, "group") == 0)
     185                    if (msg->FindString("data", &value) == B_OK)
     186                        fNotification->SetGroup(value);
    198187
    199188                if (strcmp(property, "title") == 0)
    200                     msg->FindString("data", &fTitle);
     189                    if (msg->FindString("data", &value) == B_OK)
     190                        fNotification->SetTitle(value);
    201191
    202192                if (strcmp(property, "content") == 0)
    203                     msg->FindString("data", &fText);
     193                    if (msg->FindString("data", &value) == B_OK)
     194                        fNotification->SetContent(value);
    204195
    205196                if (strcmp(property, "icon") == 0) {
    206197                    BMessage archive;
    NotificationView::MessageReceived(BMessage* msg) 
    210201                    }
    211202                }
    212203
    213                 SetText(Application(), Title(), Text());
     204                SetText();
    214205                Invalidate();
    215206
    216207                reply.AddInt32("error", B_OK);
    NotificationView::MessageReceived(BMessage* msg) 
    222213            msg->SendReply(&reply);
    223214            break;
    224215        }
    225         case kRemoveView:
    226         {
    227             BMessage remove(kRemoveView);
    228             remove.AddPointer("view", this);
    229             BMessenger msgr(Window());
    230             msgr.SendMessage( &remove );
    231             break;
    232         }
    233216        default:
    234217            BView::MessageReceived(msg);
    235218    }
    NotificationView::MessageReceived(BMessage* msg) 
    237220
    238221
    239222void
    240 NotificationView::GetPreferredSize(float* w, float* h)
    241 {
    242     // Parent width, minus the edge padding, minus the pensize
    243     *w = fParent->ViewWidth() - (kEdgePadding * 2) - (kPenSize * 2);
    244     *h = fHeight;
    245 
    246     if (fType == B_PROGRESS_NOTIFICATION) {
    247         font_height fh;
    248         be_plain_font->GetHeight(&fh);
    249         float fontHeight = fh.ascent + fh.descent + fh.leading;
    250         *h += (kSmallPadding * 2) + (kEdgePadding * 1) + fontHeight;
    251     }
    252 }
    253 
    254 
    255 void
    256223NotificationView::Draw(BRect updateRect)
    257224{
    258225    BRect progRect;
    259226
    260227    // Draw progress background
    261     if (fType == B_PROGRESS_NOTIFICATION) {
    262         PushState();
    263 
     228    if (fNotification->Type() == B_PROGRESS_NOTIFICATION) {
    264229        font_height fh;
    265230        be_plain_font->GetHeight(&fh);
     231
    266232        float fontHeight = fh.ascent + fh.descent + fh.leading;
    267233
    268234        progRect = Bounds();
    269235        progRect.InsetBy(kEdgePadding, kEdgePadding);
    270236        progRect.top = progRect.bottom - (kSmallPadding * 2) - fontHeight;
    271         StrokeRect(progRect);
    272237
    273         BRect barRect = progRect;       
    274         barRect.InsetBy(1.0, 1.0);
    275         barRect.right *= fProgress;
    276         SetHighColor(ui_color(B_CONTROL_HIGHLIGHT_COLOR));
    277         FillRect(barRect);
     238        // Progress bar
     239        rgb_color barColor = {50, 150, 255, 255};
    278240
    279         SetHighColor(ui_color(B_PANEL_TEXT_COLOR));
     241        float progress = fNotification->Progress() * 100;
     242        BRect barFrame(2, 2, progRect.right - 2, 2 + progRect.Height() - 4);
     243
     244        float barPos = 0;
     245        if (progress == 0)
     246            barPos = barFrame.left - 1;
     247        else
     248            barPos = roundf(barFrame.left - 1
     249                + (progress * (barFrame.Width() + 3) / 100));
     250
     251        PushState();
     252            be_control_look->DrawStatusBar(this, progRect, updateRect,
     253                ui_color(B_PANEL_BACKGROUND_COLOR), barColor, barPos);
     254        PopState();
    280255
    281         BString label = "";
    282         label << (int)(fProgress * 100) << " %";
     256        // Progress text
     257        BString label;
     258        label << progress << " %";
    283259
    284260        float labelWidth = be_plain_font->StringWidth(label.String());
    285261        float labelX = progRect.left + (progRect.IntegerWidth() / 2) - (labelWidth / 2);
    286262
     263        SetHighColor(ui_color(B_PANEL_TEXT_COLOR));
    287264        SetLowColor(B_TRANSPARENT_COLOR);
    288265        SetDrawingMode(B_OP_ALPHA);
     266
    289267        DrawString(label.String(), label.Length(),
    290268            BPoint(labelX, progRect.top + fh.ascent + fh.leading + kSmallPadding));
    291 
    292         PopState();
    293269    }
    294270
    295     SetDrawingMode(B_OP_ALPHA);
    296     SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
    297 
    298271    // Icon size
    299272    float iconSize = (float)fParent->IconSize();
    300273
    NotificationView::Draw(BRect updateRect) 
    307280        font_height fh;
    308281        appLine->font.GetHeight(&fh);
    309282
    310         float title_bottom = appLine->location.y + fh.descent;
    311 
    312283        float ix = kEdgePadding;
    313         float iy = 0;
    314         if (fParent->Layout() == TitleAboveIcon)
    315             iy = title_bottom + kEdgePadding + (Bounds().Height() - title_bottom
    316                 - kEdgePadding * 2 - iconSize) / 2;
    317         else
    318             iy = (Bounds().Height() - iconSize) / 2.0;
     284        float iy = (Bounds().Height() - iconSize) / 2.0;
    319285
    320         if (fType == B_PROGRESS_NOTIFICATION)
     286        if (fNotification->Type() == B_PROGRESS_NOTIFICATION)
    321287            // Move icon up by half progress bar height if it's present
    322288            iy -= (progRect.Height() + kEdgePadding) / 2.0;
    323289
    NotificationView::Draw(BRect updateRect) 
    326292        iconRect.right = ix + iconSize;
    327293        iconRect.bottom = iy + iconSize;
    328294
     295        SetDrawingMode(B_OP_ALPHA);
     296        SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
     297
    329298        DrawBitmapAsync(fBitmap, fBitmap->Bounds(),
    330299            iconRect, B_FILTER_BITMAP_BILINEAR);
    331300    }
    NotificationView::Draw(BRect updateRect) 
    348317    closeRect.left = closeRect.right - kCloseSize;
    349318    closeRect.bottom = closeRect.top + kCloseSize;
    350319
    351     PushState();
    352         SetHighColor(detailCol);
    353         StrokeRoundRect(closeRect, kSmallPadding, kSmallPadding);
    354         BRect closeCross = closeRect.InsetByCopy(kSmallPadding, kSmallPadding);
    355         StrokeLine(closeCross.LeftTop(), closeCross.RightBottom());
    356         StrokeLine(closeCross.LeftBottom(), closeCross.RightTop());
    357     PopState();
    358 
    359     Sync();
     320    SetHighColor(detailCol);
     321    StrokeRoundRect(closeRect, kSmallPadding, kSmallPadding);
     322    BRect closeCross = closeRect.InsetByCopy(kSmallPadding, kSmallPadding);
     323    StrokeLine(closeCross.LeftTop(), closeCross.RightBottom());
     324    StrokeLine(closeCross.LeftBottom(), closeCross.RightTop());
    360325}
    361326
    362327
    NotificationView::MouseDown(BPoint point) 
    366331    int32 buttons;
    367332    Window()->CurrentMessage()->FindInt32("buttons", &buttons);
    368333
    369     switch (buttons) {
    370         case B_PRIMARY_MOUSE_BUTTON:
    371         {
    372             BRect closeRect = Bounds().InsetByCopy(2,2);
    373             closeRect.left = closeRect.right - kCloseSize;
    374             closeRect.bottom = closeRect.top + kCloseSize; 
    375 
    376             if (!closeRect.Contains(point)) {
    377                 entry_ref launchRef;
    378                 BString launchString;
    379                 BMessage argMsg(B_ARGV_RECEIVED);
    380                 BMessage refMsg(B_REFS_RECEIVED);
    381                 entry_ref appRef;
    382                 bool useArgv = false;
    383                 BList messages;
    384                 entry_ref ref;
    385 
    386                 if (fDetails->FindString("onClickApp", &launchString) == B_OK)
    387                     if (be_roster->FindApp(launchString.String(), &appRef) == B_OK)
    388                         useArgv = true;
    389                 if (fDetails->FindRef("onClickFile", &launchRef) == B_OK) {
    390                     if (be_roster->FindApp(&launchRef, &appRef) == B_OK)
    391                         useArgv = true;
    392                 }
    393 
    394                 if (fDetails->FindRef("onClickRef", &ref) == B_OK) {           
    395                     for (int32 i = 0; fDetails->FindRef("onClickRef", i, &ref) == B_OK; i++)
    396                         refMsg.AddRef("refs", &ref);
    397 
    398                     messages.AddItem((void*)&refMsg);
    399                 }
     334    if ((buttons & B_PRIMARY_MOUSE_BUTTON) == 0)
     335        return;
    400336
    401                 if (useArgv) {
    402                     type_code type;
    403                     int32 argc = 0;
    404                     BString arg;
     337    BRect closeRect = Bounds().InsetByCopy(2, 2);
     338    closeRect.left = closeRect.right - kCloseSize;
     339    closeRect.bottom = closeRect.top + kCloseSize; 
     340
     341    if (!closeRect.Contains(point)) {
     342        BMessage argMsg(B_ARGV_RECEIVED);
     343        BMessage refMsg(B_REFS_RECEIVED);
     344        entry_ref appRef;
     345        bool useArgv = false;
     346        BList messages;
     347        entry_ref ref;
     348
     349        if (fNotification->OnClickApp() != NULL)
     350            if (be_roster->FindApp(fNotification->OnClickApp(), &appRef) == B_OK)
     351                useArgv = true;
     352        if (fNotification->OnClickFile() != NULL)
     353            if (be_roster->FindApp((entry_ref*)fNotification->OnClickFile(), &appRef) == B_OK)
     354                useArgv = true;
     355
     356        for (int32 i = 0; i < fNotification->CountOnClickRefs(); i++)
     357            refMsg.AddRef("refs", fNotification->OnClickRefAt(i));
     358        messages.AddItem((void*)&refMsg);
     359
     360        if (useArgv) {
     361            BString arg;
     362
     363            BPath p(&appRef);
     364            argMsg.AddString("argv", p.Path());
     365
     366            int32 argc = fNotification->CountOnClickArgs() + 1;
     367            argMsg.AddInt32("argc", argc);
     368
     369            for (int32 i = 0; i < fNotification->CountOnClickArgs(); i++)
     370                argMsg.AddString("argv", fNotification->OnClickArgAt(i));
     371            messages.AddItem((void*)&argMsg);
     372        }
    405373
    406                     BPath p(&appRef);
    407                     argMsg.AddString("argv", p.Path());
     374#if 0
     375        BMessage tmp;
     376        for (int32 i = 0; fDetails->FindMessage("onClickMsg", i, &tmp) == B_OK; i++)
     377            messages.AddItem((void*)&tmp);
     378#endif
    408379
    409                     fDetails->GetInfo("onClickArgv", &type, &argc);
    410                     argMsg.AddInt32("argc", argc + 1);
     380        if (fNotification->OnClickApp() != NULL)
     381            be_roster->Launch(fNotification->OnClickApp(), &messages);
     382        else
     383            be_roster->Launch(fNotification->OnClickFile(), &messages);
     384    }
    411385
    412                     for (int32 i = 0; fDetails->FindString("onClickArgv", i, &arg) == B_OK; i++)
    413                         argMsg.AddString("argv", arg);
     386    // Remove the info view after a click
     387    BMessage remove_msg(kRemoveView);
     388    remove_msg.AddPointer("view", this);
    414389
    415                     messages.AddItem((void*)&argMsg);
    416                 }
     390    BMessenger msgr(Parent());
     391    msgr.SendMessage(&remove_msg);
     392}
    417393
    418                 BMessage tmp;
    419                 for (int32 i = 0; fDetails->FindMessage("onClickMsg", i, &tmp) == B_OK; i++)
    420                     messages.AddItem((void*)&tmp);
    421394
    422                 if (fDetails->FindString("onClickApp", &launchString) == B_OK)
    423                     be_roster->Launch(launchString.String(), &messages);
    424                 else
    425                     be_roster->Launch(&launchRef, &messages);
    426             }
     395BSize
     396NotificationView::MinSize()
     397{
     398    return BLayoutUtils::ComposeSize(ExplicitMinSize(), _CalculateSize());
     399}
    427400
    428             // Remove the info view after a click
    429             BMessage remove_msg(kRemoveView);
    430             remove_msg.AddPointer("view", this);
    431401
    432             BMessenger msgr(Parent());
    433             msgr.SendMessage(&remove_msg);
    434             break;
    435         }
    436     }
     402BSize
     403NotificationView::MaxSize()
     404{
     405    return BLayoutUtils::ComposeSize(ExplicitMaxSize(), _CalculateSize());
    437406}
    438407
    439408
    440 void
    441 NotificationView::FrameResized( float w, float /*h*/)
     409BSize
     410NotificationView::PreferredSize()
    442411{
    443     SetText(Application(), Title(), Text());
     412    return BLayoutUtils::ComposeSize(ExplicitPreferredSize(),
     413        _CalculateSize());
    444414}
    445415
    446416
    447417BHandler*
    448 NotificationView::ResolveSpecifier(BMessage* msg, int32 index, BMessage* spec, int32 form, const char* prop)
     418NotificationView::ResolveSpecifier(BMessage* msg, int32 index, BMessage* spec,
     419    int32 form, const char* prop)
    449420{
    450421    BPropertyInfo prop_info(message_prop_list);
    451422    if (prop_info.FindMatch(msg, index, spec, form, prop) >= 0) {
    NotificationView::GetSupportedSuites(BMessage* msg) 
    467438}
    468439
    469440
    470 const char*
    471 NotificationView::Application() const
    472 {
    473     return fApp.Length() > 0 ? fApp.String() : NULL;
    474 }
    475 
    476 
    477 const char*
    478 NotificationView::Title() const
    479 {
    480     return fTitle.Length() > 0 ? fTitle.String() : NULL;
    481 }
    482 
    483 
    484 const char*
    485 NotificationView::Text() const
    486 {
    487     return fText.Length() > 0 ? fText.String() : NULL;
    488 }
    489 
    490 
    491441void
    492 NotificationView::SetText(const char* app, const char* title, const char* text,
    493     float newMaxWidth)
     442NotificationView::SetText(float newMaxWidth)
    494443{
    495444    if (newMaxWidth < 0)
    496445        newMaxWidth = Bounds().Width() - (kEdgePadding * 2);
    NotificationView::SetText(const char* app, const char* title, const char* text, 
    501450        delete (*lIt);
    502451    fLines.clear();
    503452
    504     fApp = app;
    505     fTitle = title;
    506     fText = text;
    507 
    508453    float iconRight = kEdgePadding + kEdgePadding;
    509454    if (fBitmap != NULL)
    510455        iconRight += fParent->IconSize();
    NotificationView::SetText(const char* app, const char* title, const char* text, 
    517462
    518463    // Title
    519464    LineInfo* titleLine = new LineInfo;
    520     titleLine->text = fTitle;
     465    titleLine->text = fNotification->Title();
    521466    titleLine->font = *be_bold_font;
    522 
    523     if (fParent->Layout() == AllTextRightOfIcon)
    524         titleLine->location = BPoint(iconRight, y);
    525     else
    526         titleLine->location = BPoint(kEdgePadding, y);
     467    titleLine->location = BPoint(iconRight, y);
    527468
    528469    fLines.push_front(titleLine);
    529470    y += fontHeight;
    530471
    531     // Rest of text is rendered with be_plain_font.
     472    // Rest of text is rendered with be_plain_font
    532473    be_plain_font->GetHeight(&fh);
    533474    fontHeight = ceilf(fh.leading) + ceilf(fh.descent)
    534475        + ceilf(fh.ascent);
    535476
    536     // Split text into chunks between certain characters and compose the lines.
     477    // Split text into chunks between certain characters and compose the lines
    537478    const char kSeparatorCharacters[] = " \n-\\/";
    538     BString textBuffer = fText;
     479    BString textBuffer = fNotification->Content();
    539480    textBuffer.ReplaceAll("\t", "    ");
    540481    const char* chunkStart = textBuffer.String();
    541482    float maxWidth = newMaxWidth - kEdgePadding - iconRight;
    NotificationView::SetText(const char* app, const char* title, const char* text, 
    544485    while (chunkStart - textBuffer.String() < length) {
    545486        size_t chunkLength = strcspn(chunkStart, kSeparatorCharacters) + 1;
    546487
    547         // Start a new line if either we didn't start one before,
    548         // the current offset
     488        // Start a new line if we didn't start one before
    549489        BString tempText;
    550490        if (line != NULL)
    551491            tempText.SetTo(line->text);
    NotificationView::SetText(const char* app, const char* title, const char* text, 
    560500            fLines.push_front(line);
    561501            y += fontHeight;
    562502
    563             // Skip the eventual new-line character at the beginning of this
    564             // chunk.
     503            // Skip the eventual new-line character at the beginning of this chunk
    565504            if (chunkStart[0] == '\n') {
    566505                chunkStart++;
    567506                chunkLength--;
    568507            }
    569             // Skip more new-line characters and move the line further down.
     508
     509            // Skip more new-line characters and move the line further down
    570510            while (chunkStart[0] == '\n') {
    571511                chunkStart++;
    572512                chunkLength--;
    573513                line->location.y += fontHeight;
    574514                y += fontHeight;
    575515            }
    576             // Strip space at beginning of a new line.
     516
     517            // Strip space at beginning of a new line
    577518            while (chunkStart[0] == ' ') {
    578519                chunkLength--;
    579520                chunkStart++;
    NotificationView::SetText(const char* app, const char* title, const char* text, 
    584525            break;
    585526
    586527        // Append the chunk to the current line, which was either a new
    587         // line or the one from the previous iteration.
     528        // line or the one from the previous iteration
    588529        line->text.Append(chunkStart, chunkLength);
    589530
    590531        chunkStart += chunkLength;
    NotificationView::SetText(const char* app, const char* title, const char* text, 
    594535
    595536    // Make sure icon fits
    596537    if (fBitmap != NULL) {
    597         float minHeight = 0;
    598         if (fParent->Layout() == TitleAboveIcon) {
    599             LineInfo* appLine = fLines.back();
    600             font_height fh;
    601             appLine->font.GetHeight(&fh);
    602             minHeight = appLine->location.y + fh.descent;
    603         }
     538        float minHeight = fBitmap->Bounds().Height() + 2 * kEdgePadding;
    604539
    605         minHeight += fBitmap->Bounds().Height() + 2 * kEdgePadding;
    606540        if (fHeight < minHeight)
    607541            fHeight = minHeight;
    608542    }
    609 
    610     BMessenger messenger(Parent());
    611     messenger.SendMessage(kResizeToFit);
    612 }
    613 
    614 
    615 bool
    616 NotificationView::HasMessageID(const char* id)
    617 {
    618     return fMessageID == id;
    619543}
    620544
    621545
    622546const char*
    623 NotificationView::MessageID()
    624 {
    625     return fMessageID.String();
    626 }
    627 
    628 
    629 void
    630 NotificationView::SetPosition(bool first, bool last)
    631 {
    632     fIsFirst = first;
    633     fIsLast = last;
    634 }
    635 
    636 
    637 BBitmap*
    638 NotificationView::_ReadNodeIcon(const char* fileName, icon_size size)
     547NotificationView::MessageID() const
    639548{
    640     BEntry entry(fileName, true);
    641 
    642     entry_ref ref;
    643     entry.GetRef(&ref);
    644 
    645     BNode node(BPath(&ref).Path());
    646 
    647     BBitmap* ret = new BBitmap(BRect(0, 0, (float)size - 1, (float)size - 1), B_RGBA32);
    648     if (BIconUtils::GetIcon(&node, kIconAttribute, kSmallIconAttribute,
    649         kLargeIconAttribute, size, ret) != B_OK) {
    650         delete ret;
    651         ret = NULL;
    652     }
    653 
    654     return ret;
     549    return fNotification->MessageID();
    655550}
    656551
    657552
    658 void
    659 NotificationView::_LoadIcon()
     553BSize
     554NotificationView::_CalculateSize()
    660555{
    661     // First try to get the icon from the caller application
    662     app_info info;
    663     BMessenger msgr = fDetails->ReturnAddress();
     556    BSize size;
    664557
    665     if (msgr.IsValid())
    666         be_roster->GetRunningAppInfo(msgr.Team(), &info);
    667     else if (fType == B_PROGRESS_NOTIFICATION)
    668         be_roster->GetAppInfo("application/x-vnd.Haiku-notification_server",
    669             &info);
    670 
    671     BPath path;
    672     path.SetTo(&info.ref);
    673 
    674     fBitmap = _ReadNodeIcon(path.Path(), fParent->IconSize());
    675     if (fBitmap)
    676         return;
    677 
    678     // If that failed get icons from app_server
    679     if (find_directory(B_BEOS_SERVERS_DIRECTORY, &path) != B_OK)
    680         return;
    681 
    682     path.Append("app_server");
    683 
    684     BFile file(path.Path(), B_READ_ONLY);
    685     if (file.InitCheck() != B_OK)
    686         return;
    687 
    688     BResources res(&file);
    689     if (res.InitCheck() != B_OK)
    690         return;
    691 
    692     // Which one should we choose?
    693     const char* iconName = "";
    694     switch (fType) {
    695         case B_INFORMATION_NOTIFICATION:
    696             iconName = "info";
    697             break;
    698         case B_ERROR_NOTIFICATION:
    699             iconName = "stop";
    700             break;
    701         case B_IMPORTANT_NOTIFICATION:
    702             iconName = "warn";
    703             break;
    704         default:
    705             return;
    706     }
     558    // Parent width, minus the edge padding, minus the pensize
     559    size.width = fParent->Width() - (kEdgePadding * 2) - (kPenSize * 2);
     560    size.height = fHeight;
    707561
    708     // Allocate the bitmap
    709     fBitmap = new BBitmap(BRect(0, 0, (float)B_LARGE_ICON - 1,
    710         (float)B_LARGE_ICON - 1), B_RGBA32);
    711     if (!fBitmap || fBitmap->InitCheck() != B_OK) {
    712         fBitmap = NULL;
    713         return;
     562    if (fNotification->Type() == B_PROGRESS_NOTIFICATION) {
     563        font_height fh;
     564        be_plain_font->GetHeight(&fh);
     565        float fontHeight = fh.ascent + fh.descent + fh.leading;
     566        size.height += (kSmallPadding * 2) + (kEdgePadding * 1) + fontHeight;
    714567    }
    715568
    716     // Load raw icon data
    717     size_t size = 0;
    718     const uint8* data = (const uint8*)res.LoadResource(B_VECTOR_ICON_TYPE,
    719         iconName, &size);
    720     if ((data == NULL
    721         || BIconUtils::GetVectorIcon(data, size, fBitmap) != B_OK))
    722         fBitmap = NULL;
     569    return size;
    723570}
  • src/servers/notification/NotificationView.h

    diff --git a/src/servers/notification/NotificationView.h b/src/servers/notification/NotificationView.h
    index fb2fa07..46588a5 100644
    a b  
    1111#include <list>
    1212
    1313#include <Bitmap.h>
    14 #include <Entry.h>
    15 #include <Message.h>
    1614#include <MessageRunner.h>
    17 #include <MimeType.h>
    1815#include <Notification.h>
    19 #include <Path.h>
    20 #include <Roster.h>
    21 #include <String.h>
    22 #include <TextView.h>
    2316#include <View.h>
    2417
    2518class NotificationWindow;
    const uint32 kRemoveView = 'ReVi'; 
    2922class NotificationView : public BView {
    3023public:
    3124                                NotificationView(NotificationWindow* win,
    32                                     notification_type type,
    33                                     const char* app, const char* title,
    34                                     const char* text, BMessage* details);
     25                                    BNotification* notification,
     26                                    bigtime_t timeout = -1);
    3527    virtual                     ~NotificationView();
    3628
    3729    virtual void                AttachedToWindow();
    3830    virtual void                MessageReceived(BMessage* message);
    39     virtual void                GetPreferredSize(float* width, float* height);
    4031    virtual void                Draw(BRect updateRect);
    4132    virtual void                MouseDown(BPoint point);
    42     virtual void                FrameResized(float width, float height);
     33
     34    virtual BSize               MinSize();
     35    virtual BSize               MaxSize();
     36    virtual BSize               PreferredSize();
    4337
    4438    virtual BHandler*           ResolveSpecifier(BMessage* msg, int32 index,
    4539                                    BMessage* specifier, int32 form,
    4640                                    const char* property);
    4741    virtual status_t            GetSupportedSuites(BMessage* msg);
    4842
    49             const char*         Application() const;
    50             const char*         Title() const;
    51             const char*         Text() const;
     43            void                SetText(float newMaxWidth = -1);
    5244
    53             void                SetText(const char* app, const char* title,
    54                                     const char* text, float newMaxWidth = -1);
    55             bool                HasMessageID(const char* id);
    56             const char*         MessageID();
    57             void                SetPosition(bool first, bool last);
     45            const char*         MessageID() const;
    5846
    5947private:
    60             BBitmap*            _ReadNodeIcon(const char* fileName,
    61                                     icon_size size);
    62             void                _LoadIcon();
     48            BSize               _CalculateSize();
    6349
    64 private:
    6550            struct LineInfo {
    6651                BFont   font;
    6752                BString text;
    private: 
    7055
    7156            typedef std::list<LineInfo*> LineInfoList;
    7257
    73 
    7458            NotificationWindow* fParent;
     59            BNotification*      fNotification;
     60            bigtime_t           fTimeout;
    7561
    76             notification_type   fType;
    7762            BMessageRunner*     fRunner;
    78             float               fProgress;
    79             BString             fMessageID;
    8063
    81             BMessage*           fDetails;
    8264            BBitmap*            fBitmap;
    8365
    8466            LineInfoList        fLines;
    8567
    86             BString             fApp;
    87             BString             fTitle;
    88             BString             fText;
    89 
    9068            float               fHeight;
    91 
    92             bool                fIsFirst;
    93             bool                fIsLast;
    9469};
    9570
    9671#endif  // _NOTIFICATION_VIEW_H
  • src/servers/notification/NotificationWindow.cpp

    diff --git a/src/servers/notification/NotificationWindow.cpp b/src/servers/notification/NotificationWindow.cpp
    index 74b54be..6a20d1e 100644
    a b  
    1515
    1616#include <Alert.h>
    1717#include <Application.h>
    18 #include <Debug.h>
    1918#include <File.h>
     19#include <GroupLayout.h>
     20#include <GroupLayoutBuilder.h>
    2021#include <NodeMonitor.h>
     22#include <Path.h>
    2123#include <PropertyInfo.h>
    2224
    2325#include "AppGroupView.h"
    2426#include "AppUsage.h"
    25 #include "BorderView.h"
    2627#include "NotificationWindow.h"
    2728
    2829property_info main_prop_list[] = {
    29     { "message", {B_GET_PROPERTY, 0}, {B_INDEX_SPECIFIER, 0}, "get a message"},
    30     { "message", {B_COUNT_PROPERTIES, 0}, {B_DIRECT_SPECIFIER, 0}, "count messages"},
    31     { "message", {B_CREATE_PROPERTY, 0}, {B_DIRECT_SPECIFIER, 0}, "create a message"},
    32     { "message", {B_SET_PROPERTY, 0}, {B_INDEX_SPECIFIER, 0 }, "modify a message" },
    33     0
     30    {
     31        "message",
     32        { B_GET_PROPERTY, 0 },
     33        { B_INDEX_SPECIFIER, 0 },
     34        "get a message"
     35    },
     36    {
     37        "message",
     38        { B_COUNT_PROPERTIES, 0 },
     39        { B_DIRECT_SPECIFIER, 0 },
     40        "count messages"
     41    },
     42    {
     43        "message",
     44        { B_CREATE_PROPERTY, 0 },
     45        { B_DIRECT_SPECIFIER, 0 },
     46        "create a message"
     47    },
     48    {
     49        "message",
     50        { B_SET_PROPERTY, 0 },
     51        { B_INDEX_SPECIFIER, 0 },
     52        "modify a message"
     53    },
     54    { 0, { 0 }, { 0 }, 0, 0 }
    3455};
    3556
    36 const float kCloseSize              = 8;
    37 const float kExpandSize             = 8;
    38 const float kPenSize                = 1;
    39 const float kEdgePadding            = 5;
    40 const float kSmallPadding           = 2;
     57const float kCloseSize = 8;
     58const float kExpandSize = 8;
     59const float kPenSize = 1;
     60const float kEdgePadding = 5;
     61const float kSmallPadding = 2;
    4162
    4263
    4364NotificationWindow::NotificationWindow()
    4465    :
    45     BWindow(BRect(10, 10, 30, 30), "Notification", B_BORDERED_WINDOW,
     66    BWindow(BRect(0, 0, -1, -1), "Notification", B_BORDERED_WINDOW,
    4667        B_AVOID_FRONT | B_AVOID_FOCUS | B_NOT_CLOSABLE | B_NOT_ZOOMABLE
    47             | B_NOT_MINIMIZABLE | B_NOT_RESIZABLE, B_ALL_WORKSPACES)
     68            | B_NOT_MINIMIZABLE | B_NOT_RESIZABLE | B_AUTO_UPDATE_SIZE_LIMITS,
     69        B_ALL_WORKSPACES)
    4870{
    49     fBorder = new BorderView(Bounds(), "Notification");
     71    BGroupLayout* layout = new BGroupLayout(B_VERTICAL, 10);
     72    layout->SetInsets(5, 5, 5, 5);
    5073
    51     AddChild(fBorder);
     74    fView = new BView("top", B_WILL_DRAW, layout);
     75    fView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
    5276
     77    SetLayout(new BGroupLayout(B_VERTICAL));
     78    AddChild(BGroupLayoutBuilder(B_VERTICAL)
     79        .Add(fView)
     80    );
     81
     82    // The first Show() starts the loop so we have to call Show() and Hide(),
     83    // after moving the window out of sight - I'm not sure if Run() is more
     84    // appropriate
     85    MoveTo(-1, -1);
    5386    Show();
    5487    Hide();
    5588
    56     LoadSettings(true);
    57     LoadAppFilters(true);
     89    _LoadSettings(true);
     90    _LoadAppFilters(true);
    5891}
    5992
    6093
    6194NotificationWindow::~NotificationWindow()
    6295{
    63     appfilter_t::iterator aIt;
    64     for (aIt = fAppFilters.begin(); aIt != fAppFilters.end(); aIt++)
    65         delete aIt->second;
     96    appfilter_t::iterator fIt;
     97    for (fIt = fAppFilters.begin(); fIt != fAppFilters.end(); ++fIt)
     98        delete fIt->second;
     99
     100    appview_t::iterator gIt;
     101    for (gIt = fAppViews.begin(); gIt != fAppViews.end(); ++gIt) {
     102        fView->GetLayout()->RemoveView(gIt->second);
     103        delete gIt->second;
     104    }
    66105}
    67106
    68107
    69108bool
    70109NotificationWindow::QuitRequested()
    71110{
    72     appview_t::iterator aIt;
    73     for (aIt = fAppViews.begin(); aIt != fAppViews.end(); aIt++) {
    74         aIt->second->RemoveSelf();
    75         delete aIt->second;
    76     }
    77 
    78     BMessenger(be_app).SendMessage(B_QUIT_REQUESTED);
    79     return BWindow::QuitRequested();
     111    be_app_messenger.SendMessage(B_QUIT_REQUESTED);
     112    return true;
    80113}
    81114
    82115
    83116void
    84 NotificationWindow::WorkspaceActivated(int32 /*workspace*/, bool active)
     117NotificationWindow::WorkspaceActivated(int32 workspace, bool active)
    85118{
    86     // Ensure window is in the correct position
    87119    if (active)
    88         ResizeAll();
     120        // Ensure window is in the current position
     121        _ResizeAll();
    89122}
    90123
    91124
    NotificationWindow::MessageReceived(BMessage* message) 
    95128    switch (message->what) {
    96129        case B_NODE_MONITOR:
    97130        {
    98             LoadSettings();
    99             LoadAppFilters();
     131            _LoadSettings();
     132            _LoadAppFilters();
    100133            break;
    101134        }
    102         case kResizeToFit:
    103             ResizeAll();
    104             break;
    105135        case B_COUNT_PROPERTIES:
    106136        {
    107137            BMessage reply(B_REPLY);
    NotificationWindow::MessageReceived(BMessage* message) 
    129159        case B_CREATE_PROPERTY:
    130160        case kNotificationMessage:
    131161        {
    132             int32 type;
    133             const char* content = NULL;
    134             const char* title = NULL;
    135             const char* app = NULL;
    136162            BMessage reply(B_REPLY);
    137             bool messageOkay = true;
     163            BNotification* notification = new BNotification(message);
    138164
    139             if (message->FindInt32("type", &type) != B_OK)
    140                 type = B_INFORMATION_NOTIFICATION;
    141             if (message->FindString("content", &content) != B_OK)
    142                 messageOkay = false;
    143             if (message->FindString("title", &title) != B_OK)
    144                 messageOkay = false;
    145             if (message->FindString("app", &app) != B_OK && message->FindString("appTitle", &app) != B_OK)
    146                 messageOkay = false;
     165            if (notification->InitCheck() == B_OK) {
     166                // Time out
     167                bigtime_t timeout;
     168                if (message->FindInt64("timeout", &timeout) != B_OK)
     169                    timeout = -1;
    147170
    148             if (messageOkay) {
    149                 NotificationView* view = new NotificationView(this, (notification_type)type, app,
    150                     title, content, new BMessage(*message));
     171                // Determine sender's signature
     172                BMessenger messenger = message->ReturnAddress();
     173                app_info info;
    151174
    152                 appfilter_t::iterator fIt = fAppFilters.find(app);
    153                 bool allow = false;
    154                 if (fIt == fAppFilters.end()) {
    155                     app_info info;
    156                     BMessenger messenger = message->ReturnAddress();
    157                     if (messenger.IsValid())
    158                         be_roster->GetRunningAppInfo(messenger.Team(), &info);
    159                     else
    160                         be_roster->GetAppInfo("application/x-vnd.Be-SHEL", &info);
     175                if (messenger.IsValid())
     176                    be_roster->GetRunningAppInfo(messenger.Team(), &info);
     177                else
     178                    be_roster->GetAppInfo("application/x-vnd.Be-SHEL", &info);
    161179
    162                     AppUsage* appUsage = new AppUsage(info.ref, app, true);
    163                     fAppFilters[app] = appUsage;
     180                NotificationView* view = new NotificationView(this, notification,
     181                    timeout);
    164182
    165                     appUsage->Allowed(title, (notification_type)type);
     183                bool allow = false;
     184                appfilter_t::iterator it = fAppFilters.find(info.signature);
    166185
     186                if (it == fAppFilters.end()) {
     187                    AppUsage* appUsage = new AppUsage(notification->Group(), true);
     188                    appUsage->Allowed(notification->Title(), notification->Type());
     189                    fAppFilters[info.signature] = appUsage;
    167190                    allow = true;
    168191                } else
    169                     allow = fIt->second->Allowed(title, (notification_type)type);
     192                    allow = it->second->Allowed(notification->Title(), notification->Type());
     193                _SaveAppFilters();
    170194
    171195                if (allow) {
    172                     appview_t::iterator aIt = fAppViews.find(app);
    173                     AppGroupView *group = NULL;
     196                    BString groupName(notification->Group());
     197                    AppGroupView* group = NULL;
     198                    appview_t::iterator aIt = fAppViews.find(groupName);
     199
    174200                    if (aIt == fAppViews.end()) {
    175                         group = new AppGroupView(this, app);
    176                         fAppViews[app] = group;
    177                         fBorder->AddChild(group);
    178                     } else {
     201                        group = new AppGroupView(this,
     202                            groupName == "" ? NULL : groupName.String());
     203                        fAppViews[groupName] = group;
     204                        fView->GetLayout()->AddView(group);
     205                    } else
    179206                        group = aIt->second;
    180                     };
    181                     group->AddInfo(view);
    182                        
    183                     ResizeAll();
    184                    
     207
     208                    if (group) {
     209                        group->AddInfo(view);
     210                        fViews.push_back(view);
     211                    }
     212
     213                    _ResizeAll();
     214
    185215                    reply.AddInt32("error", B_OK);
    186216                } else
    187                     reply.AddInt32("Error", B_ERROR);
     217                    reply.AddInt32("error", B_ERROR);
    188218            } else {
    189219                reply.what = B_MESSAGE_NOT_UNDERSTOOD;
    190220                reply.AddInt32("error", B_ERROR);
    NotificationWindow::MessageReceived(BMessage* message) 
    195225        }
    196226        case kRemoveView:
    197227        {
    198             void* _ptr;
    199             message->FindPointer("view", &_ptr);
    200 
    201             NotificationView* info
    202                 = reinterpret_cast<NotificationView*>(_ptr);
     228            NotificationView* view = NULL;
     229            if (message->FindPointer("view", (void**)&view) != B_OK)
     230                return;
    203231
    204             fBorder->RemoveChild(info);
     232            views_t::iterator it = find(fViews.begin(), fViews.end(), view);
    205233
    206             std::vector<NotificationView*>::iterator i
    207                 = find(fViews.begin(), fViews.end(), info);
    208             if (i != fViews.end())
    209                 fViews.erase(i);
     234            if (it != fViews.end())
     235                fViews.erase(it);
    210236
    211             delete info;
    212 
    213             ResizeAll();
     237            _ResizeAll();
    214238            break;
    215239        }
    216240        default:
    NotificationWindow::ResolveSpecifier(BMessage *msg, int32 index, 
    266290
    267291
    268292icon_size
    269 NotificationWindow::IconSize()
     293NotificationWindow::IconSize() const
    270294{
    271295    return fIconSize;
    272296}
    273297
    274298
    275299int32
    276 NotificationWindow::Timeout()
     300NotificationWindow::Timeout() const
    277301{
    278302    return fTimeout;
    279303}
    280304
    281305
    282306
    283 infoview_layout
    284 NotificationWindow::Layout()
    285 {
    286     return fLayout;
    287 }
    288 
    289 
    290307float
    291 NotificationWindow::ViewWidth()
     308NotificationWindow::Width() const
    292309{
    293310    return fWidth;
    294311}
    295312
    296313
    297314void
    298 NotificationWindow::ResizeAll()
     315NotificationWindow::_ResizeAll()
    299316{
     317    // Hide if no group views are available
    300318    if (fAppViews.empty()) {
    301319        if (!IsHidden())
    302320            Hide();
    NotificationWindow::ResizeAll() 
    307325    bool shouldHide = true;
    308326
    309327    for (aIt = fAppViews.begin(); aIt != fAppViews.end(); aIt++) {
    310         AppGroupView *app = aIt->second;
    311         if (app->HasChildren()) {
     328        AppGroupView* groupView = aIt->second;
     329
     330        // We should not hide the notification window if at least
     331        // one group view has children
     332        if (groupView->HasChildren())
    312333            shouldHide = false;
    313             break;
    314         }
     334        else if (!groupView->IsHidden())
     335            groupView->Hide();
    315336    }
    316337
    317     if (shouldHide) {
    318         if (!IsHidden())
    319             Hide();
     338    if (shouldHide && !IsHidden()) {
     339        Hide();
    320340        return;
    321341    }
    322342
    323     if (IsHidden())
    324         Show();
    325 
    326     float width = 0;
    327     float height = 0;
    328 
    329     for (aIt = fAppViews.begin(); aIt != fAppViews.end(); aIt++) {
    330         AppGroupView* view = aIt->second;
    331         float w = -1;
    332         float h = -1;
    333 
    334         if (!view->HasChildren()) {
    335             if (!view->IsHidden())
    336                 view->Hide();
    337         } else {
    338             view->GetPreferredSize(&w, &h);
    339             width = max_c(width, h);
    340 
    341             view->ResizeToPreferred();
    342             view->MoveTo(0, height);
    343 
    344             height += h;
    345 
    346             if (view->IsHidden())
    347                 view->Show();
    348         }
    349     }
    350 
    351     ResizeTo(ViewWidth(), height);
    352     PopupAnimation(Bounds().Width(), Bounds().Height());
     343    _PopupAnimation();
    353344}
    354345
    355346
    356347void
    357 NotificationWindow::PopupAnimation(float width, float height)
     348NotificationWindow::_PopupAnimation()
    358349{
     350    float width = Width();
     351    float height = fView->Bounds().Height();
     352
    359353    float x = 0, y = 0, sx, sy;
    360354    float pad = 0;
    361355    BDeskbar deskbar;
    NotificationWindow::PopupAnimation(float width, float height) 
    365359        case B_DESKBAR_TOP:
    366360            // Put it just under, top right corner
    367361            sx = frame.right;
    368             sy = frame.bottom+pad;
     362            sy = frame.bottom + pad;
    369363            y = sy;
    370             x = sx-width-pad;
     364            x = sx - width - pad;
    371365            break;
    372366        case B_DESKBAR_BOTTOM:
    373367            // Put it just above, lower left corner
    374368            sx = frame.right;
    375             sy = frame.top-height-pad;
     369            sy = frame.top - height - pad;
    376370            y = sy;
    377             x = sx - width-pad;
     371            x = sx - width - pad;
    378372            break;
    379373        case B_DESKBAR_LEFT_TOP:
    380374            // Put it just to the right of the deskbar
    381             sx = frame.right+pad;
    382             sy = frame.top-height;
     375            sx = frame.right + pad;
     376            sy = frame.top - height;
    383377            x = sx;
    384             y = frame.top+pad;
     378            y = frame.top + pad;
    385379            break;
    386380        case B_DESKBAR_RIGHT_TOP:
    387381            // Put it just to the left of the deskbar
    388             sx = frame.left-width-pad;
    389             sy = frame.top-height;
     382            sx = frame.left - width - pad;
     383            sy = frame.top - height;
    390384            x = sx;
    391             y = frame.top+pad;
     385            y = frame.top + pad;
    392386            break;
    393387        case B_DESKBAR_LEFT_BOTTOM:
    394388            // Put it to the right of the deskbar.
    395             sx = frame.right+pad;
     389            sx = frame.right + pad;
    396390            sy = frame.bottom;
    397391            x = sx;
    398             y = sy-height-pad;
     392            y = sy - height - pad;
    399393            break;
    400394        case B_DESKBAR_RIGHT_BOTTOM:
    401395            // Put it to the left of the deskbar.
    402             sx = frame.left-width-pad;
     396            sx = frame.left - width - pad;
    403397            sy = frame.bottom;
    404             y = sy-height-pad;
     398            y = sy - height - pad;
    405399            x = sx;
    406400            break; 
    407401        default:
    NotificationWindow::PopupAnimation(float width, float height) 
    409403    }
    410404
    411405    MoveTo(x, y);
    412    
    413     if (IsHidden() && fViews.size() != 0)
     406
     407    if (IsHidden())
    414408        Show();
    415     //Activate();// it hides floaters from apps :-(
    416409}
    417410
    418411
    419412void
    420 NotificationWindow::LoadSettings(bool startMonitor)
     413NotificationWindow::_LoadSettings(bool startMonitor)
    421414{
    422415    _LoadGeneralSettings(startMonitor);
    423416    _LoadDisplaySettings(startMonitor);
    NotificationWindow::LoadSettings(bool startMonitor) 
    425418
    426419
    427420void
    428 NotificationWindow::LoadAppFilters(bool startMonitor)
     421NotificationWindow::_LoadAppFilters(bool startMonitor)
    429422{
    430423    BPath path;
    431424
    NotificationWindow::LoadAppFilters(bool startMonitor) 
    471464
    472465
    473466void
    474 NotificationWindow::SaveAppFilters()
     467NotificationWindow::_SaveAppFilters()
    475468{
    476469    BPath path;
    477470
    NotificationWindow::_LoadGeneralSettings(bool startMonitor) 
    516509    views_t::iterator it;
    517510    for (it = fViews.begin(); it != fViews.end(); ++it) {
    518511        NotificationView* view = (*it);
    519         view->SetText(view->Application(), view->Title(), view->Text());
    520512        view->Invalidate();
    521513    }
    522514
    NotificationWindow::_LoadGeneralSettings(bool startMonitor) 
    526518        entry.GetNodeRef(&nref);
    527519
    528520        if (watch_node(&nref, B_WATCH_ALL, BMessenger(this)) != B_OK) {
    529             BAlert* alert = new BAlert("", "Couldn't start general settings "
    530                 " monitor.\nLive filter changes disabled.", "OK");
     521            BAlert* alert = new BAlert("", "Notification service: Couldn't start "
     522                "general settings monitor.\nLive filter changes disabled.", "OK");
    531523            alert->Go();
    532524        }
    533525    }
    NotificationWindow::_LoadDisplaySettings(bool startMonitor) 
    561553    else
    562554        fIconSize = (icon_size)setting;
    563555
    564     if (settings.FindInt32(kLayoutName, &setting) != B_OK)
    565         fLayout = kDefaultLayout;
    566     else {
    567         switch (setting) {
    568             case 0:
    569                 fLayout = TitleAboveIcon;
    570                 break;
    571             case 1:
    572                 fLayout = AllTextRightOfIcon;
    573                 break;
    574             default:
    575                 fLayout = kDefaultLayout;
    576         }
    577     }
    578 
    579556    // Notify the view about the change
    580557    views_t::iterator it;
    581558    for (it = fViews.begin(); it != fViews.end(); ++it) {
    582559        NotificationView* view = (*it);
    583         view->SetText(view->Application(), view->Title(), view->Text());
    584560        view->Invalidate();
    585561    }
    586562
    NotificationWindow::_LoadDisplaySettings(bool startMonitor) 
    590566        entry.GetNodeRef(&nref);
    591567
    592568        if (watch_node(&nref, B_WATCH_ALL, BMessenger(this)) != B_OK) {
    593             BAlert* alert = new BAlert("", "Couldn't start display settings "
    594                 " monitor.\nLive filter changes disabled.", "OK");
     569            BAlert* alert = new BAlert("", "Notification service: Couldn't start "
     570                "display settings monitor.\nLive filter changes disabled.", "OK");
    595571            alert->Go();
    596572        }
    597573    }
  • src/servers/notification/NotificationWindow.h

    diff --git a/src/servers/notification/NotificationWindow.h b/src/servers/notification/NotificationWindow.h
    index a246f7e..29ed9b3 100644
    a b  
    2626
    2727class AppGroupView;
    2828class AppUsage;
    29 class BorderView;
    30 class SettingsFile;
    3129
    3230typedef std::map<BString, AppGroupView*> appview_t;
    3331typedef std::map<BString, AppUsage*> appfilter_t;
    extern const float kCloseSize; 
    3937extern const float kExpandSize;
    4038extern const float kPenSize;
    4139
    42 const uint32 kResizeToFit = 'IWrf';
    43 
    4440class NotificationWindow : public BWindow {
    4541public:
    4642                                    NotificationWindow();
    public: 
    4844
    4945    virtual bool                    QuitRequested();
    5046    virtual void                    MessageReceived(BMessage*);
    51     virtual void                    WorkspaceActivated(int32, bool);
     47    virtual void                    WorkspaceActivated(int32 workspace, bool active);
    5248    virtual BHandler*               ResolveSpecifier(BMessage*, int32, BMessage*,
    5349                                        int32, const char*);
    5450
    55             icon_size               IconSize();
    56             int32                   Timeout();
    57             infoview_layout         Layout();
    58             float                   ViewWidth();
    59 
    60             void                    ResizeAll();
     51            icon_size               IconSize() const;
     52            int32                   Timeout() const;
     53            float                   Width() const;
    6154
    6255private:
    63     friend class AppGroupView;
     56            void                    _ResizeAll();
     57
     58            void                    _PopupAnimation();
    6459
    65             void                    PopupAnimation(float, float);
    66             void                    LoadSettings(bool startMonitor = false);
    67             void                    LoadAppFilters(bool startMonitor = false);
    68             void                    SaveAppFilters();
     60            void                    _LoadSettings(bool startMonitor = false);
     61            void                    _LoadAppFilters(bool startMonitor = false);
     62            void                    _SaveAppFilters();
    6963            void                    _LoadGeneralSettings(bool startMonitor);
    7064            void                    _LoadDisplaySettings(bool startMonitor);
    7165
    72             views_t                 fViews;
    73             BorderView*             fBorder;
     66            BView*                  fView;
    7467
     68            views_t                 fViews;
    7569            appview_t               fAppViews;
    7670
    7771            BString                 fStatusText;
    private: 
    8074            float                   fWidth;
    8175            icon_size               fIconSize;
    8276            int32                   fTimeout;
    83             infoview_layout         fLayout;
    8477
    8578            appfilter_t             fAppFilters;
    8679};