Patch by plfiorini: Integration of InfoPopper as a system service. See ticket
#1245. There are some TODOs outlined in the ticket, but they will be much easier to review as individual patches against trunk, versus as a new version of the huge patch. I've messed a lot with src/servers/notification/NotificationsView.cpp in order to resolve a crash I was getting when testing this thing (rewrote line wrapping). I've also replaced the icons with the one that zuMi did long ago. Thanks, plfiorini, for working on this code as much as you did! git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@36949 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
279d26af87
commit
de9dcd41f8
|
@ -44,7 +44,7 @@ SYSTEM_BIN = "[" addattr alert arp base64 basename bash bc beep bootman bzip2
|
|||
listport listres listsem listusb ln locate logger login logname ls lsindex
|
||||
mail2mbox makebootable mbox2mail md5sum merge message mimeset mkdos mkdir
|
||||
mkfifo mkfs mkindex mktemp modifiers mount mount_nfs mountvolume mv
|
||||
netcat netstat nl nohup nproc
|
||||
netcat netstat nl nohup notify nproc
|
||||
od open
|
||||
passwd paste patch pathchk pc ping play playfile playsound playwav pr prio
|
||||
printenv printf profile ps ptx pwd
|
||||
|
@ -70,7 +70,7 @@ SYSTEM_APPS = AboutSystem ActivityMonitor CharacterMap CodyCam DeskCalc Devices
|
|||
;
|
||||
SYSTEM_PREFERENCES = Appearance Backgrounds CPUFrequency DataTranslations
|
||||
<preference>Deskbar E-mail FileTypes Fonts Keyboard Keymap Locale Media
|
||||
Mouse Network OpenGL Printers Screen ScreenSaver Shortcuts Sounds Time
|
||||
Mouse Network Notifications OpenGL Printers Screen ScreenSaver Shortcuts Sounds Time
|
||||
Touchpad <preference>Tracker VirtualMemory
|
||||
;
|
||||
SYSTEM_DEMOS = BSnow Chart Clock Cortex FontDemo
|
||||
|
@ -103,7 +103,7 @@ PRIVATE_SYSTEM_LIBS =
|
|||
;
|
||||
SYSTEM_SERVERS = app_server cddb_daemon debug_server input_server mail_daemon
|
||||
media_addon_server media_server midi_server mount_server net_server
|
||||
print_server registrar syslog_daemon
|
||||
notification_server print_server registrar syslog_daemon
|
||||
;
|
||||
|
||||
SYSTEM_NETWORK_DEVICES = ethernet loopback ;
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _NOTIFICATION_H
|
||||
#define _NOTIFICATION_H
|
||||
|
||||
#include <Entry.h>
|
||||
|
||||
// notification types
|
||||
enum notification_type {
|
||||
B_INFORMATION_NOTIFICATION,
|
||||
B_IMPORTANT_NOTIFICATION,
|
||||
B_ERROR_NOTIFICATION,
|
||||
B_PROGRESS_NOTIFICATION
|
||||
};
|
||||
|
||||
class BBitmap;
|
||||
class BList;
|
||||
|
||||
class BNotification {
|
||||
public:
|
||||
BNotification(notification_type type);
|
||||
~BNotification();
|
||||
|
||||
notification_type Type() const;
|
||||
|
||||
const char* Application() const;
|
||||
void SetApplication(const char* app);
|
||||
|
||||
const char* Title() const;
|
||||
void SetTitle(const char* title);
|
||||
|
||||
const char* Content() const;
|
||||
void SetContent(const char* content);
|
||||
|
||||
const char* MessageID() const;
|
||||
void SetMessageID(const char* id);
|
||||
|
||||
float Progress() const;
|
||||
void SetProgress(float progress);
|
||||
|
||||
const char* OnClickApp() const;
|
||||
void SetOnClickApp(const char* app);
|
||||
|
||||
entry_ref* OnClickFile() const;
|
||||
void SetOnClickFile(const entry_ref* file);
|
||||
|
||||
BList* OnClickRefs() const;
|
||||
void AddOnClickRef(const entry_ref* ref);
|
||||
|
||||
BList* OnClickArgv() const;
|
||||
void AddOnClickArg(const char* arg);
|
||||
|
||||
BBitmap* Icon() const;
|
||||
void SetIcon(BBitmap* icon);
|
||||
|
||||
private:
|
||||
notification_type fType;
|
||||
char* fAppName;
|
||||
char* fTitle;
|
||||
char* fContent;
|
||||
char* fID;
|
||||
float fProgress;
|
||||
char* fApp;
|
||||
entry_ref* fFile;
|
||||
BList* fRefs;
|
||||
BList* fArgv;
|
||||
BBitmap* fBitmap;
|
||||
};
|
||||
|
||||
#endif // _NOTIFICATION_H
|
|
@ -13,6 +13,7 @@
|
|||
class BFile;
|
||||
class BMimeType;
|
||||
class BNodeInfo;
|
||||
class BNotification;
|
||||
|
||||
|
||||
struct app_info {
|
||||
|
@ -116,6 +117,10 @@ class BRoster {
|
|||
void AddToRecentFolders(const entry_ref *folder,
|
||||
const char *appSig = 0) const;
|
||||
|
||||
// notifications
|
||||
status_t Notify(BNotification* notification,
|
||||
int32 timeout = -1) const;
|
||||
|
||||
// private/reserved stuff starts here
|
||||
class Private;
|
||||
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2008-2009, Pier Luigi Fiorini. All Rights Reserved.
|
||||
* Copyright 2004-2008, Michael Davidson. All Rights Reserved.
|
||||
* Copyright 2004-2007, Mikael Eiman. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _APP_USAGE_H
|
||||
#define _APP_USAGE_H
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <Entry.h>
|
||||
#include <Flattenable.h>
|
||||
#include <Notification.h>
|
||||
#include <Roster.h>
|
||||
#include <String.h>
|
||||
|
||||
class BMessage;
|
||||
class NotificationReceived;
|
||||
|
||||
typedef std::map<BString, NotificationReceived*> notify_t;
|
||||
|
||||
class AppUsage : public BFlattenable {
|
||||
public:
|
||||
AppUsage();
|
||||
AppUsage(entry_ref ref, const char* name,
|
||||
bool allow = true);
|
||||
~AppUsage();
|
||||
|
||||
virtual bool AllowsTypeCode(type_code code) const;
|
||||
virtual status_t Flatten(void* buffer, ssize_t numBytes) const;
|
||||
virtual ssize_t FlattenedSize() const;
|
||||
virtual bool IsFixedSize() const;
|
||||
virtual type_code TypeCode() const;
|
||||
virtual status_t Unflatten(type_code code, const void* buffer,
|
||||
ssize_t numBytes);
|
||||
|
||||
entry_ref Ref();
|
||||
const char* Name();
|
||||
bool Allowed(const char* title, notification_type type);
|
||||
bool Allowed();
|
||||
NotificationReceived* NotificationAt(int32 index);
|
||||
int32 Notifications();
|
||||
void AddNotification(NotificationReceived* notification);
|
||||
|
||||
private:
|
||||
entry_ref fRef;
|
||||
BString fName;
|
||||
bool fAllow;
|
||||
notify_t fNotifications;
|
||||
};
|
||||
|
||||
#endif // _APP_USAGE_H
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2008-2009, Pier Luigi Fiorini. All Rights Reserved.
|
||||
* Copyright 2004-2008, Michael Davidson. All Rights Reserved.
|
||||
* Copyright 2004-2007, Mikael Eiman. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _NOTIFICATION_RECEIVED_H
|
||||
#define _NOTIFICATION_RECEIVED_H
|
||||
|
||||
#include <Flattenable.h>
|
||||
#include <Roster.h>
|
||||
#include <String.h>
|
||||
|
||||
class NotificationReceived : public BFlattenable {
|
||||
public:
|
||||
NotificationReceived();
|
||||
NotificationReceived(const char* title, notification_type type,
|
||||
bool enabled = true);
|
||||
~NotificationReceived();
|
||||
|
||||
virtual bool AllowsTypeCode(type_code code) const;
|
||||
virtual status_t Flatten(void *buffer, ssize_t numBytes) const;
|
||||
virtual ssize_t FlattenedSize() const;
|
||||
virtual bool IsFixedSize() const;
|
||||
virtual type_code TypeCode() const;
|
||||
virtual status_t Unflatten(type_code code, const void *buffer,
|
||||
ssize_t numBytes);
|
||||
|
||||
const char* Title();
|
||||
notification_type Type();
|
||||
void SetType(notification_type type);
|
||||
time_t LastReceived();
|
||||
bool Allowed();
|
||||
|
||||
void SetTimeStamp(time_t time);
|
||||
void UpdateTimeStamp();
|
||||
|
||||
private:
|
||||
BString fTitle;
|
||||
notification_type fType;
|
||||
bool fEnabled;
|
||||
time_t fLastReceived;
|
||||
};
|
||||
|
||||
#endif // _NOTIFICATION_RECEIVED_H
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _NOTIFICATIONS_H
|
||||
#define _NOTIFICATIONS_H
|
||||
|
||||
#include <Mime.h>
|
||||
|
||||
#define kNotificationServerSignature "application/x-vnd.Haiku-notification_server"
|
||||
|
||||
// Messages
|
||||
const uint32 kNotificationMessage = 'nssm';
|
||||
|
||||
// Notification layout
|
||||
enum infoview_layout {
|
||||
TitleAboveIcon = 0,
|
||||
AllTextRightOfIcon = 1
|
||||
};
|
||||
|
||||
// Settings constants
|
||||
extern const char* kSettingsDirectory;
|
||||
extern const char* kFiltersSettings;
|
||||
extern const char* kGeneralSettings;
|
||||
extern const char* kDisplaySettings;
|
||||
|
||||
// General settings
|
||||
extern const char* kAutoStartName;
|
||||
extern const char* kTimeoutName;
|
||||
|
||||
// General default settings
|
||||
const float kDefaultAutoStart = false;
|
||||
const int32 kDefaultTimeout = 10;
|
||||
|
||||
// Display settings
|
||||
extern const char* kWidthName;
|
||||
extern const char* kIconSizeName;
|
||||
extern const char* kLayoutName;
|
||||
|
||||
// Display default settings
|
||||
const float kDefaultWidth = 300.0f;
|
||||
const icon_size kDefaultIconSize = B_LARGE_ICON;
|
||||
const infoview_layout kDefaultLayout = TitleAboveIcon;
|
||||
|
||||
#endif // _NOTIFICATIONS_H
|
|
@ -9,6 +9,7 @@ UsePrivateSystemHeaders ;
|
|||
SubDirHdrs $(HAIKU_TOP) src add-ons kernel file_cache ;
|
||||
UseLibraryHeaders ncurses ;
|
||||
UseLibraryHeaders termcap ;
|
||||
UseLibraryHeaders icon ;
|
||||
|
||||
local haiku-utils_rsrc = [ FGristFiles haiku-utils.rsrc ] ;
|
||||
|
||||
|
@ -157,6 +158,11 @@ StdBinCommands
|
|||
translate.cpp
|
||||
: be translation $(TARGET_LIBSUPC++) : $(haiku-utils_rsrc) ;
|
||||
|
||||
# standard commands that need libbe.so, libtranslation.so, libicon.a, libstdc++.so
|
||||
StdBinCommands
|
||||
notify.cpp
|
||||
: be translation libicon.a $(TARGET_LIBSTDC++) : $(haiku-utils_rsrc) ;
|
||||
|
||||
# standard commands that need libbe.so, libmedia.so
|
||||
StdBinCommands
|
||||
installsound.cpp
|
||||
|
|
|
@ -0,0 +1,325 @@
|
|||
/*
|
||||
* Copyright 2010, Haiku, Inc. All rights reserved.
|
||||
* Copyright 2008, Pier Luigi Fiorini.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <Application.h>
|
||||
#include <Bitmap.h>
|
||||
#include <IconUtils.h>
|
||||
#include <List.h>
|
||||
#include <Mime.h>
|
||||
#include <Notification.h>
|
||||
#include <Path.h>
|
||||
#include <Roster.h>
|
||||
#include <TranslationUtils.h>
|
||||
|
||||
const char* kSignature = "application/x-vnd.Haiku-notify";
|
||||
const char* kSmallIconAttribute = "BEOS:M:STD_ICON";
|
||||
const char* kLargeIconAttribute = "BEOS:L:STD_ICON";
|
||||
const char* kIconAttribute = "BEOS:ICON";
|
||||
|
||||
const char *kTypeNames[] = {
|
||||
"information",
|
||||
"important",
|
||||
"error",
|
||||
"progress",
|
||||
NULL
|
||||
};
|
||||
|
||||
const int32 kErrorInitFail = 127;
|
||||
const int32 kErrorArgumentsFail = 126;
|
||||
|
||||
class NotifyApp : public BApplication {
|
||||
public:
|
||||
NotifyApp();
|
||||
virtual ~NotifyApp();
|
||||
|
||||
virtual void ReadyToRun();
|
||||
virtual void ArgvReceived(int32 argc, char** argv);
|
||||
|
||||
bool GoodArguments() const { return fOk; }
|
||||
|
||||
private:
|
||||
bool fOk;
|
||||
notification_type fType;
|
||||
const char* fAppName;
|
||||
const char* fTitle;
|
||||
const char* fMsgId;
|
||||
float fProgress;
|
||||
int32 fTimeout;
|
||||
const char* fIconFile;
|
||||
entry_ref fFileRef;
|
||||
const char* fMessage;
|
||||
const char* fApp;
|
||||
bool fHasFile;
|
||||
entry_ref fFile;
|
||||
BList* fRefs;
|
||||
BList* fArgv;
|
||||
|
||||
void _Usage() const;
|
||||
BBitmap* _GetBitmap(const entry_ref* ref) const;
|
||||
};
|
||||
|
||||
|
||||
NotifyApp::NotifyApp()
|
||||
:
|
||||
BApplication(kSignature),
|
||||
fOk(false),
|
||||
fType(B_INFORMATION_NOTIFICATION),
|
||||
fAppName(NULL),
|
||||
fTitle(NULL),
|
||||
fMsgId(NULL),
|
||||
fProgress(0.0f),
|
||||
fTimeout(0),
|
||||
fIconFile(NULL),
|
||||
fMessage(NULL),
|
||||
fApp(NULL),
|
||||
fHasFile(false)
|
||||
{
|
||||
fRefs = new BList();
|
||||
fArgv = new BList();
|
||||
}
|
||||
|
||||
|
||||
NotifyApp::~NotifyApp()
|
||||
{
|
||||
if (fAppName)
|
||||
free((void*)fAppName);
|
||||
if (fTitle)
|
||||
free((void*)fTitle);
|
||||
if (fMsgId)
|
||||
free((void*)fMsgId);
|
||||
if (fIconFile)
|
||||
free((void*)fIconFile);
|
||||
if (fMessage)
|
||||
free((void*)fMessage);
|
||||
if (fApp)
|
||||
free((void*)fApp);
|
||||
|
||||
int32 i;
|
||||
void* item;
|
||||
|
||||
for (i = 0; item = fRefs->ItemAt(i); i++)
|
||||
delete item;
|
||||
delete fRefs;
|
||||
|
||||
for (i = 0; item = fArgv->ItemAt(i); i++) {
|
||||
if (item != NULL)
|
||||
free(item);
|
||||
}
|
||||
delete fArgv;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NotifyApp::ArgvReceived(int32 argc, char** argv)
|
||||
{
|
||||
const uint32 kArgCount = argc - 1;
|
||||
uint32 index = 1;
|
||||
|
||||
// Look for valid options
|
||||
for (; index <= kArgCount; ++index) {
|
||||
if (argv[index][0] == '-' && argv[index][1] == '-') {
|
||||
const char* option = argv[index] + 2;
|
||||
|
||||
if (++index > kArgCount) {
|
||||
// No argument to option
|
||||
fprintf(stderr, "Missing argument to option --%s\n\n", option);
|
||||
return;
|
||||
}
|
||||
|
||||
const char* argument = argv[index];
|
||||
|
||||
if (strcmp(option, "type") == 0) {
|
||||
for (int32 i = 0; kTypeNames[i]; i++) {
|
||||
if (strncmp(kTypeNames[i], argument, strlen(argument)) == 0)
|
||||
fType = (notification_type)i;
|
||||
}
|
||||
} else if (strcmp(option, "app") == 0) {
|
||||
fAppName = strdup(argument);
|
||||
} else if (strcmp(option, "title") == 0) {
|
||||
fTitle = strdup(argument);
|
||||
} else if (strcmp(option, "messageID") == 0) {
|
||||
fMsgId = strdup(argument);
|
||||
} else if (strcmp(option, "progress") == 0) {
|
||||
fProgress = atof(argument);
|
||||
} else if (strcmp(option, "timeout") == 0) {
|
||||
fTimeout = atol(argument);
|
||||
} else if (strcmp(option, "icon") == 0) {
|
||||
fIconFile = strdup(argument);
|
||||
|
||||
if (get_ref_for_path(fIconFile, &fFileRef) < B_OK) {
|
||||
fprintf(stderr, "Bad icon path!\n\n");
|
||||
return;
|
||||
}
|
||||
} else if (strcmp(option, "onClickApp") == 0)
|
||||
fApp = strdup(argument);
|
||||
else if (strcmp(option, "onClickFile") == 0) {
|
||||
if (get_ref_for_path(argument, &fFile) != B_OK) {
|
||||
fprintf(stderr, "Bad path for --onClickFile!\n\n");
|
||||
return;
|
||||
}
|
||||
|
||||
fHasFile = true;
|
||||
} else if (strcmp(option, "onClickRef") == 0) {
|
||||
entry_ref ref;
|
||||
|
||||
if (get_ref_for_path(argument, &ref) != B_OK) {
|
||||
fprintf(stderr, "Bad path for --onClickRef!\n\n");
|
||||
return;
|
||||
}
|
||||
|
||||
fRefs->AddItem((void*)new BEntry(&ref));
|
||||
} else if (strcmp(option, "onClickArgv") == 0)
|
||||
fArgv->AddItem((void*)strdup(argument));
|
||||
else {
|
||||
// Unrecognized option
|
||||
fprintf(stderr, "Unrecognized option --%s\n\n", option);
|
||||
return;
|
||||
}
|
||||
} else
|
||||
// Option doesn't start with '--'
|
||||
break;
|
||||
|
||||
if (index == kArgCount) {
|
||||
// No text argument provided, only '--' arguments
|
||||
fprintf(stderr, "Missing message argument!\n\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for missing arguments
|
||||
if (!fAppName) {
|
||||
fprintf(stderr, "Missing --app argument!\n\n");
|
||||
return;
|
||||
}
|
||||
if (!fTitle) {
|
||||
fprintf(stderr, "Missing --title argument!\n\n");
|
||||
return;
|
||||
}
|
||||
|
||||
fMessage = strdup(argv[index]);
|
||||
fOk = true;
|
||||
}
|
||||
|
||||
void
|
||||
NotifyApp::_Usage() const
|
||||
{
|
||||
fprintf(stderr, "Usage: notify [OPTION]... [MESSAGE]\n"
|
||||
"Send notifications to notification_server.\n"
|
||||
" --type <type>\tNotification type,\n"
|
||||
" \t <type>: ");
|
||||
|
||||
for (int32 i = 0; kTypeNames[i]; i++)
|
||||
fprintf(stderr, kTypeNames[i + 1] ? "%s|" : "%s\n", kTypeNames[i]);
|
||||
|
||||
fprintf(stderr,
|
||||
" --app <app name>\tApplication name\n"
|
||||
" --title <title>\tMessage title\n"
|
||||
" --messageID <msg id>\tMessage ID\n"
|
||||
" --progress <float>\tProgress, value between 0.0 and 1.0 - if type is set to progress\n"
|
||||
" --timeout <secs>\tSpecify timeout\n"
|
||||
" --onClickApp <signature>\tApplication to open when notification is clicked\n"
|
||||
" --onClickFile <fullpath>\tFile to open when notification is clicked\n"
|
||||
" --onClickRef <fullpath>\tFile to open with the application when notification is clicked\n"
|
||||
" --onClickArgv <arg>\tArgument to the application when notification is clicked\n"
|
||||
" --icon <icon file> Icon\n");
|
||||
}
|
||||
|
||||
|
||||
BBitmap*
|
||||
NotifyApp::_GetBitmap(const entry_ref* ref) const
|
||||
{
|
||||
BBitmap* bitmap = NULL;
|
||||
|
||||
// First try by contents
|
||||
bitmap = BTranslationUtils::GetBitmap(ref);
|
||||
if (bitmap)
|
||||
return bitmap;
|
||||
|
||||
// Then, try reading its attribute
|
||||
BNode node(BPath(ref).Path());
|
||||
bitmap = new BBitmap(BRect(0, 0, (float)B_LARGE_ICON - 1,
|
||||
(float)B_LARGE_ICON - 1), B_RGBA32);
|
||||
if (BIconUtils::GetIcon(&node, kIconAttribute, kSmallIconAttribute,
|
||||
kLargeIconAttribute, B_LARGE_ICON, bitmap) != B_OK) {
|
||||
delete bitmap;
|
||||
bitmap = NULL;
|
||||
}
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NotifyApp::ReadyToRun()
|
||||
{
|
||||
if (GoodArguments()) {
|
||||
BNotification* msg = new BNotification(fType);
|
||||
msg->SetApplication(fAppName);
|
||||
msg->SetTitle(fTitle);
|
||||
msg->SetContent(fMessage);
|
||||
|
||||
if (fMsgId)
|
||||
msg->SetMessageID(fMsgId);
|
||||
|
||||
if (fType == B_PROGRESS_NOTIFICATION)
|
||||
msg->SetProgress(fProgress);
|
||||
|
||||
if (fIconFile) {
|
||||
BBitmap* bitmap = _GetBitmap(&fFileRef);
|
||||
if (bitmap)
|
||||
msg->SetIcon(bitmap);
|
||||
}
|
||||
|
||||
if (fApp)
|
||||
msg->SetOnClickApp(fApp);
|
||||
|
||||
if (fHasFile)
|
||||
msg->SetOnClickFile(&fFile);
|
||||
|
||||
int32 i;
|
||||
void* item;
|
||||
|
||||
for (i = 0; item = fRefs->ItemAt(i); i++) {
|
||||
BEntry* entry = (BEntry*)item;
|
||||
|
||||
entry_ref ref;
|
||||
if (entry->GetRef(&ref) == B_OK)
|
||||
msg->AddOnClickRef(&ref);
|
||||
}
|
||||
|
||||
for (i = 0; item = fArgv->ItemAt(i); i++) {
|
||||
const char* arg = (const char*)item;
|
||||
msg->AddOnClickArg(arg);
|
||||
}
|
||||
|
||||
be_roster->Notify(msg, fTimeout);
|
||||
} else
|
||||
_Usage();
|
||||
|
||||
Quit();
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char** argv)
|
||||
{
|
||||
NotifyApp app;
|
||||
if (app.InitCheck() != B_OK)
|
||||
return kErrorInitFail;
|
||||
|
||||
app.Run();
|
||||
if (!app.GoodArguments())
|
||||
return kErrorArgumentsFail;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -81,6 +81,7 @@ SubInclude HAIKU_TOP src kits media ;
|
|||
SubInclude HAIKU_TOP src kits midi ;
|
||||
SubInclude HAIKU_TOP src kits midi2 ;
|
||||
SubInclude HAIKU_TOP src kits network ;
|
||||
SubInclude HAIKU_TOP src kits notification ;
|
||||
SubInclude HAIKU_TOP src kits opengl ;
|
||||
SubInclude HAIKU_TOP src kits print ;
|
||||
SubInclude HAIKU_TOP src kits screensaver ;
|
||||
|
|
|
@ -17,7 +17,7 @@ if $(RUN_WITHOUT_APP_SERVER) != 0 {
|
|||
SubDirC++Flags $(defines) ;
|
||||
}
|
||||
|
||||
UsePrivateHeaders shared app interface kernel ;
|
||||
UsePrivateHeaders shared app interface kernel notification ;
|
||||
UsePrivateSystemHeaders ;
|
||||
|
||||
SetSubDirSupportedPlatforms haiku libbe_test ;
|
||||
|
@ -45,6 +45,7 @@ MergeObject <libbe>app_kit.o :
|
|||
MessageRunner.cpp
|
||||
Messenger.cpp
|
||||
MessageUtils.cpp
|
||||
Notification.cpp
|
||||
PropertyInfo.cpp
|
||||
PortLink.cpp
|
||||
RegistrarDefs.cpp
|
||||
|
|
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Pier Luigi Fiorini, pierluigi.fiorini@gmail.com
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <Bitmap.h>
|
||||
#include <List.h>
|
||||
#include <Message.h>
|
||||
#include <Notification.h>
|
||||
|
||||
|
||||
BNotification::BNotification(notification_type type)
|
||||
:
|
||||
fType(type),
|
||||
fAppName(NULL),
|
||||
fTitle(NULL),
|
||||
fContent(NULL),
|
||||
fID(NULL),
|
||||
fApp(NULL),
|
||||
fFile(NULL),
|
||||
fBitmap(NULL)
|
||||
{
|
||||
fRefs = new BList();
|
||||
fArgv = new BList();
|
||||
}
|
||||
|
||||
|
||||
BNotification::~BNotification()
|
||||
{
|
||||
if (fAppName)
|
||||
free(fAppName);
|
||||
if (fTitle)
|
||||
free(fTitle);
|
||||
if (fContent)
|
||||
free(fContent);
|
||||
if (fID)
|
||||
free(fID);
|
||||
if (fApp)
|
||||
free(fApp);
|
||||
|
||||
delete fRefs;
|
||||
delete fArgv;
|
||||
}
|
||||
|
||||
|
||||
notification_type
|
||||
BNotification::Type() const
|
||||
{
|
||||
return fType;
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
BNotification::Application() const
|
||||
{
|
||||
return fAppName;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BNotification::SetApplication(const char* app)
|
||||
{
|
||||
free(fAppName);
|
||||
fAppName = NULL;
|
||||
|
||||
if (app)
|
||||
fAppName = strdup(app);
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
BNotification::Title() const
|
||||
{
|
||||
return fTitle;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BNotification::SetTitle(const char* title)
|
||||
{
|
||||
free(fTitle);
|
||||
fTitle = NULL;
|
||||
|
||||
if (title)
|
||||
fTitle = strdup(title);
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
BNotification::Content() const
|
||||
{
|
||||
return fContent;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BNotification::SetContent(const char* content)
|
||||
{
|
||||
free(fContent);
|
||||
fContent = NULL;
|
||||
|
||||
if (content)
|
||||
fContent = strdup(content);
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
BNotification::MessageID() const
|
||||
{
|
||||
return fID;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BNotification::SetMessageID(const char* id)
|
||||
{
|
||||
free(fID);
|
||||
fID = NULL;
|
||||
|
||||
if (id)
|
||||
fID = strdup(id);
|
||||
}
|
||||
|
||||
|
||||
float
|
||||
BNotification::Progress() const
|
||||
{
|
||||
return fProgress;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BNotification::SetProgress(float progress)
|
||||
{
|
||||
fProgress = progress;
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
BNotification::OnClickApp() const
|
||||
{
|
||||
return fApp;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BNotification::SetOnClickApp(const char* app)
|
||||
{
|
||||
free(fApp);
|
||||
fApp = NULL;
|
||||
|
||||
if (app)
|
||||
fApp = strdup(app);
|
||||
}
|
||||
|
||||
|
||||
entry_ref*
|
||||
BNotification::OnClickFile() const
|
||||
{
|
||||
return fFile;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BNotification::SetOnClickFile(const entry_ref* file)
|
||||
{
|
||||
fFile = (entry_ref*)file;
|
||||
}
|
||||
|
||||
|
||||
BList*
|
||||
BNotification::OnClickRefs() const
|
||||
{
|
||||
return fRefs;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BNotification::AddOnClickRef(const entry_ref* ref)
|
||||
{
|
||||
fRefs->AddItem((void*)ref);
|
||||
}
|
||||
|
||||
|
||||
BList*
|
||||
BNotification::OnClickArgv() const
|
||||
{
|
||||
return fArgv;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BNotification::AddOnClickArg(const char* arg)
|
||||
{
|
||||
fArgv->AddItem((void*)arg);
|
||||
}
|
||||
|
||||
|
||||
BBitmap*
|
||||
BNotification::Icon() const
|
||||
{
|
||||
return fBitmap;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BNotification::SetIcon(BBitmap* icon)
|
||||
{
|
||||
fBitmap = icon;
|
||||
}
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include <AppFileInfo.h>
|
||||
#include <Application.h>
|
||||
#include <Bitmap.h>
|
||||
#include <Directory.h>
|
||||
#include <File.h>
|
||||
#include <FindDirectory.h>
|
||||
|
@ -35,6 +36,8 @@
|
|||
#include <Mime.h>
|
||||
#include <Node.h>
|
||||
#include <NodeInfo.h>
|
||||
#include <Notification.h>
|
||||
#include <notification/Notifications.h>
|
||||
#include <OS.h>
|
||||
#include <Path.h>
|
||||
#include <Query.h>
|
||||
|
@ -1650,6 +1653,63 @@ BRoster::AddToRecentFolders(const entry_ref* folder, const char* appSig) const
|
|||
DBG(OUT("WARNING: BRoster::AddToRecentDocuments() failed with error 0x%lx\n", err));
|
||||
}
|
||||
|
||||
/*! \brief Sends a notification to the notification_server.
|
||||
|
||||
The notification is delivered synchronously to the notification_server,
|
||||
that will displays it according to its settings and filters.
|
||||
|
||||
\param notification Notification message.
|
||||
\param timeout Seconds after the message fades out.
|
||||
\return
|
||||
- \c B_OK: Everything went fine.
|
||||
- \c B_BAD_PORT_ID: A connection to notification_server could not be
|
||||
established or the server is not up and running anymore.
|
||||
*/
|
||||
status_t
|
||||
BRoster::Notify(BNotification* notification, int32 timeout) const
|
||||
{
|
||||
BMessage msg(kNotificationMessage);
|
||||
msg.AddInt32("type", (int32)notification->Type());
|
||||
msg.AddString("app", notification->Application());
|
||||
msg.AddString("title", notification->Title());
|
||||
msg.AddString("content", notification->Content());
|
||||
|
||||
if (notification->MessageID())
|
||||
msg.AddString("messageID", notification->MessageID());
|
||||
|
||||
if (notification->Type() == B_PROGRESS_NOTIFICATION)
|
||||
msg.AddFloat("progress", notification->Progress());
|
||||
|
||||
if (notification->OnClickApp())
|
||||
msg.AddString("onClickApp", notification->OnClickApp());
|
||||
if (notification->OnClickFile())
|
||||
msg.AddRef("onClickFile", notification->OnClickFile());
|
||||
|
||||
int32 i;
|
||||
|
||||
BList* refs = notification->OnClickRefs();
|
||||
for (i = 0; i < refs->CountItems(); i++)
|
||||
msg.AddRef("onClickRef", (entry_ref*)refs->ItemAt(i));
|
||||
|
||||
BList* argv = notification->OnClickArgv();
|
||||
for (i = 0; i < argv->CountItems(); i++)
|
||||
msg.AddString("onClickArgv", (const char*)argv->ItemAt(i));
|
||||
|
||||
BBitmap* icon = notification->Icon();
|
||||
|
||||
BMessage archive;
|
||||
if (icon && icon->Archive(&archive) == B_OK)
|
||||
msg.AddMessage("icon", &archive);
|
||||
|
||||
// Custom time out
|
||||
if (timeout > 0)
|
||||
msg.AddInt32("timeout", timeout);
|
||||
|
||||
// Send message
|
||||
BMessenger server(kNotificationServerSignature);
|
||||
return server.SendMessage(&msg);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - Private or reserved
|
||||
|
||||
|
|
|
@ -0,0 +1,204 @@
|
|||
/*
|
||||
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2008-2009, Pier Luigi Fiorini. All Rights Reserved.
|
||||
* Copyright 2004-2008, Michael Davidson. All Rights Reserved.
|
||||
* Copyright 2004-2007, Mikael Eiman. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Michael Davidson, slaad@bong.com.au
|
||||
* Mikael Eiman, mikael@eiman.tv
|
||||
* Pier Luigi Fiorini, pierluigi.fiorini@gmail.com
|
||||
*/
|
||||
|
||||
#include <Message.h>
|
||||
|
||||
#include <AppUsage.h>
|
||||
#include <NotificationReceived.h>
|
||||
|
||||
const type_code kTypeCode = 'ipau';
|
||||
|
||||
|
||||
AppUsage::AppUsage()
|
||||
:
|
||||
fName(""),
|
||||
fAllow(true)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
AppUsage::AppUsage(entry_ref ref, const char* name, bool allow)
|
||||
:
|
||||
fRef(ref),
|
||||
fName(name),
|
||||
fAllow(allow)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
AppUsage::~AppUsage()
|
||||
{
|
||||
notify_t::iterator nIt;
|
||||
for (nIt = fNotifications.begin(); nIt != fNotifications.end(); nIt++)
|
||||
delete nIt->second;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
AppUsage::AllowsTypeCode(type_code code) const
|
||||
{
|
||||
return code == kTypeCode;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AppUsage::Flatten(void* buffer, ssize_t numBytes) const
|
||||
{
|
||||
BMessage msg;
|
||||
msg.AddString("app_name", fName);
|
||||
msg.AddRef("app_ref", &fRef);
|
||||
msg.AddBool("app_allow", fAllow);
|
||||
|
||||
notify_t::const_iterator nIt;
|
||||
for (nIt = fNotifications.begin(); nIt != fNotifications.end(); nIt++)
|
||||
msg.AddFlat("notify", nIt->second);
|
||||
|
||||
if (numBytes < msg.FlattenedSize())
|
||||
return B_ERROR;
|
||||
|
||||
return msg.Flatten((char*)buffer, numBytes);
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
AppUsage::FlattenedSize() const
|
||||
{
|
||||
BMessage msg;
|
||||
msg.AddString("app_name", fName);
|
||||
msg.AddRef("app_ref", &fRef);
|
||||
msg.AddBool("app_allow", fAllow);
|
||||
|
||||
notify_t::const_iterator nIt;
|
||||
for (nIt = fNotifications.begin(); nIt != fNotifications.end(); nIt++)
|
||||
msg.AddFlat("notify", nIt->second);
|
||||
|
||||
return msg.FlattenedSize();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
AppUsage::IsFixedSize() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
type_code
|
||||
AppUsage::TypeCode() const
|
||||
{
|
||||
return kTypeCode;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AppUsage::Unflatten(type_code code, const void* buffer,
|
||||
ssize_t numBytes)
|
||||
{
|
||||
if (code != kTypeCode)
|
||||
return B_ERROR;
|
||||
|
||||
BMessage msg;
|
||||
status_t status = B_ERROR;
|
||||
|
||||
status = msg.Unflatten((const char*)buffer);
|
||||
|
||||
if (status == B_OK) {
|
||||
msg.FindString("app_name", &fName);
|
||||
msg.FindRef("app_ref", &fRef);
|
||||
msg.FindBool("app_allow", &fAllow);
|
||||
|
||||
type_code type;
|
||||
int32 count = 0;
|
||||
|
||||
status = msg.GetInfo("notify", &type, &count);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
NotificationReceived *notify = new NotificationReceived();
|
||||
msg.FindFlat("notify", i, notify);
|
||||
fNotifications[notify->Title()] = notify;
|
||||
}
|
||||
|
||||
status = B_OK;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
entry_ref
|
||||
AppUsage::Ref()
|
||||
{
|
||||
return fRef;
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
AppUsage::Name()
|
||||
{
|
||||
return fName.String();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
AppUsage::Allowed(const char* title, notification_type type)
|
||||
{
|
||||
bool allowed = fAllow;
|
||||
|
||||
if (allowed) {
|
||||
notify_t::iterator nIt = fNotifications.find(title);
|
||||
if (nIt == fNotifications.end()) {
|
||||
allowed = true;
|
||||
fNotifications[title] = new NotificationReceived(title, type);
|
||||
} else {
|
||||
allowed = nIt->second->Allowed();
|
||||
nIt->second->UpdateTimeStamp();
|
||||
nIt->second->SetType(type);
|
||||
}
|
||||
}
|
||||
|
||||
return allowed;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
AppUsage::Allowed()
|
||||
{
|
||||
return fAllow;
|
||||
}
|
||||
|
||||
|
||||
NotificationReceived*
|
||||
AppUsage::NotificationAt(int32 index)
|
||||
{
|
||||
notify_t::iterator nIt = fNotifications.begin();
|
||||
for (int32 i = 0; i < index; i++)
|
||||
nIt++;
|
||||
|
||||
return nIt->second;
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
AppUsage::Notifications()
|
||||
{
|
||||
return fNotifications.size();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AppUsage::AddNotification(NotificationReceived* notification)
|
||||
{
|
||||
fNotifications[notification->Title()] = notification;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
SubDir HAIKU_TOP src kits notification ;
|
||||
|
||||
UsePrivateHeaders notification ;
|
||||
|
||||
StaticLibrary libnotification.a :
|
||||
AppUsage.cpp
|
||||
NotificationReceived.cpp
|
||||
Notifications.cpp
|
||||
;
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2008-2009, Pier Luigi Fiorini. All Rights Reserved.
|
||||
* Copyright 2004-2008, Michael Davidson. All Rights Reserved.
|
||||
* Copyright 2004-2007, Mikael Eiman. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Michael Davidson, slaad@bong.com.au
|
||||
* Mikael Eiman, mikael@eiman.tv
|
||||
* Pier Luigi Fiorini, pierluigi.fiorini@gmail.com
|
||||
*/
|
||||
|
||||
#include <Message.h>
|
||||
#include <Notification.h>
|
||||
#include <NotificationReceived.h>
|
||||
|
||||
const type_code kTypeCode = 'ipnt';
|
||||
|
||||
|
||||
NotificationReceived::NotificationReceived()
|
||||
:
|
||||
fTitle(""),
|
||||
fType(B_INFORMATION_NOTIFICATION),
|
||||
fEnabled(false),
|
||||
fLastReceived(time(NULL))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
NotificationReceived::NotificationReceived(const char* title,
|
||||
notification_type type, bool enabled)
|
||||
:
|
||||
fTitle(title),
|
||||
fType(type),
|
||||
fEnabled(enabled),
|
||||
fLastReceived(time(NULL))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
NotificationReceived::~NotificationReceived()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
NotificationReceived::AllowsTypeCode(type_code code) const
|
||||
{
|
||||
return code == kTypeCode;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
NotificationReceived::Flatten(void* buffer, ssize_t numBytes) const
|
||||
{
|
||||
BMessage msg;
|
||||
msg.AddString("notify_title", fTitle);
|
||||
msg.AddInt32("notify_type", (int32)fType);
|
||||
msg.AddInt32("notify_lastreceived", (int32)fLastReceived);
|
||||
msg.AddBool("notify_enabled", fEnabled);
|
||||
|
||||
if (numBytes < msg.FlattenedSize())
|
||||
return B_ERROR;
|
||||
|
||||
return msg.Flatten((char*)buffer, numBytes);
|
||||
}
|
||||
|
||||
|
||||
ssize_t
|
||||
NotificationReceived::FlattenedSize() const
|
||||
{
|
||||
BMessage msg;
|
||||
msg.AddString("notify_title", fTitle);
|
||||
msg.AddInt32("notify_type", (int32)fType);
|
||||
msg.AddInt32("notify_lastreceived", (int32)fLastReceived);
|
||||
msg.AddBool("notify_enabled", fEnabled);
|
||||
|
||||
return msg.FlattenedSize();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
NotificationReceived::IsFixedSize() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
type_code
|
||||
NotificationReceived::TypeCode() const
|
||||
{
|
||||
return kTypeCode;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
NotificationReceived::Unflatten(type_code code, const void* buffer,
|
||||
ssize_t numBytes)
|
||||
{
|
||||
if (code != kTypeCode)
|
||||
return B_ERROR;
|
||||
|
||||
BMessage msg;
|
||||
status_t error = msg.Unflatten((const char*)buffer);
|
||||
|
||||
if (error == B_OK) {
|
||||
msg.FindString("notify_title", &fTitle);
|
||||
msg.FindInt32("notify_type", (int32 *)&fType);
|
||||
msg.FindInt32("notify_lastreceived", (int32 *)&fLastReceived);
|
||||
msg.FindBool("notify_enabled", &fEnabled);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
NotificationReceived::Title()
|
||||
{
|
||||
return fTitle.String();
|
||||
}
|
||||
|
||||
|
||||
notification_type
|
||||
NotificationReceived::Type()
|
||||
{
|
||||
return fType;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NotificationReceived::SetType(notification_type type)
|
||||
{
|
||||
fType = type;
|
||||
}
|
||||
|
||||
|
||||
time_t
|
||||
NotificationReceived::LastReceived()
|
||||
{
|
||||
return fLastReceived;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
NotificationReceived::Allowed()
|
||||
{
|
||||
return fEnabled;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NotificationReceived::UpdateTimeStamp()
|
||||
{
|
||||
fLastReceived = time(NULL);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NotificationReceived::SetTimeStamp(time_t time)
|
||||
{
|
||||
fLastReceived = time;
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include <Notifications.h>
|
||||
|
||||
|
||||
// Settings constants
|
||||
const char* kSettingsDirectory = "system/notifications";
|
||||
const char* kFiltersSettings = "filters";
|
||||
const char* kGeneralSettings = "general";
|
||||
const char* kDisplaySettings = "display";
|
||||
|
||||
// General settings
|
||||
const char* kAutoStartName = "auto-start";
|
||||
const char* kTimeoutName = "timeout";
|
||||
|
||||
// Display settings
|
||||
const char* kWidthName = "width";
|
||||
const char* kIconSizeName = "icon size";
|
||||
const char* kLayoutName = "layout";
|
||||
|
|
@ -17,6 +17,7 @@ SubInclude HAIKU_TOP src preferences mail ;
|
|||
SubInclude HAIKU_TOP src preferences media ;
|
||||
SubInclude HAIKU_TOP src preferences mouse ;
|
||||
SubInclude HAIKU_TOP src preferences network ;
|
||||
SubInclude HAIKU_TOP src preferences notifications ;
|
||||
SubInclude HAIKU_TOP src preferences opengl ;
|
||||
SubInclude HAIKU_TOP src preferences print ;
|
||||
SubInclude HAIKU_TOP src preferences screen ;
|
||||
|
|
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2009, Pier Luigi Fiorini.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Pier Luigi Fiorini, pierluigi.fiorini@gmail.com
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <Alert.h>
|
||||
#include <Directory.h>
|
||||
#include <Message.h>
|
||||
#include <FindDirectory.h>
|
||||
#include <GroupLayout.h>
|
||||
#include <GridLayoutBuilder.h>
|
||||
#include <SpaceLayoutItem.h>
|
||||
#include <TextControl.h>
|
||||
#include <Menu.h>
|
||||
#include <MenuItem.h>
|
||||
#include <MenuField.h>
|
||||
#include <Mime.h>
|
||||
#include <Node.h>
|
||||
#include <notification/Notifications.h>
|
||||
#include <Path.h>
|
||||
|
||||
#include "DisplayView.h"
|
||||
#include "SettingsHost.h"
|
||||
|
||||
#define _T(str) (str)
|
||||
|
||||
|
||||
DisplayView::DisplayView(SettingsHost* host)
|
||||
:
|
||||
SettingsPane("display", host)
|
||||
{
|
||||
// Window width
|
||||
fWindowWidth = new BTextControl(_T("Window width:"), NULL,
|
||||
new BMessage(kSettingChanged));
|
||||
|
||||
// Icon size
|
||||
fIconSize = new BMenu("iconSize");
|
||||
fIconSize->AddItem(new BMenuItem(_T("Mini icon"),
|
||||
new BMessage(kSettingChanged)));
|
||||
fIconSize->AddItem(new BMenuItem(_T("Large icon"),
|
||||
new BMessage(kSettingChanged)));
|
||||
fIconSize->SetLabelFromMarked(true);
|
||||
fIconSizeField = new BMenuField(_T("Icon size:"), fIconSize);
|
||||
|
||||
// Title position
|
||||
fTitlePosition = new BMenu("titlePosition");
|
||||
fTitlePosition->AddItem(new BMenuItem(_T("Above icon"),
|
||||
new BMessage(kSettingChanged)));
|
||||
fTitlePosition->AddItem(new BMenuItem(_T("Right of icon"),
|
||||
new BMessage(kSettingChanged)));
|
||||
fTitlePosition->SetLabelFromMarked(true);
|
||||
fTitlePositionField = new BMenuField(_T("Title position:"), fTitlePosition);
|
||||
|
||||
// Load settings
|
||||
Load();
|
||||
|
||||
// Calculate inset
|
||||
float inset = ceilf(be_plain_font->Size() * 0.7f);
|
||||
|
||||
SetLayout(new BGroupLayout(B_VERTICAL));
|
||||
AddChild(BGridLayoutBuilder(inset, inset)
|
||||
.Add(fWindowWidth->CreateLabelLayoutItem(), 0, 0)
|
||||
.Add(fWindowWidth->CreateTextViewLayoutItem(), 1, 0)
|
||||
.Add(fIconSizeField->CreateLabelLayoutItem(), 0, 1)
|
||||
.Add(fIconSizeField->CreateMenuBarLayoutItem(), 1, 1)
|
||||
.Add(fTitlePositionField->CreateLabelLayoutItem(), 0, 2)
|
||||
.Add(fTitlePositionField->CreateMenuBarLayoutItem(), 1, 2)
|
||||
.Add(BSpaceLayoutItem::CreateGlue(), 0, 3, 2, 1)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DisplayView::AttachedToWindow()
|
||||
{
|
||||
fWindowWidth->SetTarget(this);
|
||||
fIconSize->SetTargetForItems(this);
|
||||
fTitlePosition->SetTargetForItems(this);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DisplayView::MessageReceived(BMessage* msg)
|
||||
{
|
||||
switch (msg->what) {
|
||||
case kSettingChanged:
|
||||
SettingsPane::MessageReceived(msg);
|
||||
break;
|
||||
default:
|
||||
BView::MessageReceived(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
DisplayView::Load()
|
||||
{
|
||||
BPath path;
|
||||
|
||||
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
path.Append(kSettingsDirectory);
|
||||
|
||||
if (create_directory(path.Path(), 0755) != B_OK) {
|
||||
BAlert* alert = new BAlert("",
|
||||
_T("There was a problem saving the preferences.\n"
|
||||
"It's possible you don't have write access to the "
|
||||
"settings directory."), "OK", NULL, NULL,
|
||||
B_WIDTH_AS_USUAL, B_STOP_ALERT);
|
||||
(void)alert->Go();
|
||||
}
|
||||
|
||||
path.Append(kDisplaySettings);
|
||||
|
||||
BFile file(path.Path(), B_READ_ONLY);
|
||||
BMessage settings;
|
||||
settings.Unflatten(&file);
|
||||
|
||||
char buffer[255];
|
||||
int32 setting;
|
||||
BMenuItem* item = NULL;
|
||||
|
||||
float width;
|
||||
if (settings.FindFloat(kWidthName, &width) != B_OK)
|
||||
width = kDefaultWidth;
|
||||
(void)sprintf(buffer, "%.2f", width);
|
||||
fWindowWidth->SetText(buffer);
|
||||
|
||||
icon_size iconSize;
|
||||
if (settings.FindInt32(kIconSizeName, &setting) != B_OK)
|
||||
iconSize = kDefaultIconSize;
|
||||
else
|
||||
iconSize = (icon_size)setting;
|
||||
if (iconSize == B_MINI_ICON)
|
||||
item = fIconSize->ItemAt(0);
|
||||
else
|
||||
item = fIconSize->ItemAt(1);
|
||||
if (item)
|
||||
item->SetMarked(true);
|
||||
|
||||
infoview_layout layout;
|
||||
if (settings.FindInt32(kLayoutName, &setting) != B_OK)
|
||||
layout = kDefaultLayout;
|
||||
else {
|
||||
switch (setting) {
|
||||
case 0:
|
||||
layout = TitleAboveIcon;
|
||||
break;
|
||||
case 1:
|
||||
layout = AllTextRightOfIcon;
|
||||
break;
|
||||
default:
|
||||
layout = kDefaultLayout;
|
||||
}
|
||||
}
|
||||
item = fTitlePosition->ItemAt(layout);
|
||||
if (item)
|
||||
item->SetMarked(true);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
DisplayView::Save()
|
||||
{
|
||||
BPath path;
|
||||
|
||||
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
path.Append(kSettingsDirectory);
|
||||
path.Append(kDisplaySettings);
|
||||
|
||||
BMessage settings;
|
||||
|
||||
float width = atof(fWindowWidth->Text());
|
||||
settings.AddFloat(kWidthName, width);
|
||||
|
||||
icon_size iconSize = kDefaultIconSize;
|
||||
switch (fIconSize->IndexOf(fIconSize->FindMarked())) {
|
||||
case 0:
|
||||
iconSize = B_MINI_ICON;
|
||||
break;
|
||||
default:
|
||||
iconSize = B_LARGE_ICON;
|
||||
}
|
||||
settings.AddInt32(kIconSizeName, (int32)iconSize);
|
||||
|
||||
int32 layout = fTitlePosition->IndexOf(fTitlePosition->FindMarked());
|
||||
if (layout == B_ERROR)
|
||||
layout = (int32)kDefaultLayout;
|
||||
settings.AddInt32(kLayoutName, layout);
|
||||
|
||||
// Save settings file
|
||||
BFile file(path.Path(), B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
|
||||
status_t ret = settings.Flatten(&file);
|
||||
if (ret != B_OK) {
|
||||
BAlert* alert = new BAlert("",
|
||||
_T("Can't save preferenes, you probably don't have write "
|
||||
"access to the settings directory or the disk is full."), "OK", NULL, NULL,
|
||||
B_WIDTH_AS_USUAL, B_STOP_ALERT);
|
||||
(void)alert->Go();
|
||||
return ret;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
DisplayView::Revert()
|
||||
{
|
||||
return B_ERROR;
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2009, Pier Luigi Fiorini.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _DISPLAY_VIEW_H
|
||||
#define _DISPLAY_VIEW_H
|
||||
|
||||
#include "SettingsPane.h"
|
||||
|
||||
class BTextControl;
|
||||
class BMenu;
|
||||
class BMenuField;
|
||||
|
||||
class DisplayView : public SettingsPane {
|
||||
public:
|
||||
DisplayView(SettingsHost* host);
|
||||
|
||||
virtual void AttachedToWindow();
|
||||
virtual void MessageReceived(BMessage* msg);
|
||||
|
||||
// SettingsPane hooks
|
||||
status_t Load();
|
||||
status_t Save();
|
||||
status_t Revert();
|
||||
|
||||
private:
|
||||
BTextControl* fWindowWidth;
|
||||
BMenu* fIconSize;
|
||||
BMenuField* fIconSizeField;
|
||||
BMenu* fTitlePosition;
|
||||
BMenuField* fTitlePositionField;
|
||||
|
||||
};
|
||||
|
||||
#endif // _DISPLAY_VIEW_H
|
|
@ -0,0 +1,364 @@
|
|||
/*
|
||||
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2009, Pier Luigi Fiorini.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Pier Luigi Fiorini, pierluigi.fiorini@gmail.com
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <Roster.h>
|
||||
#include <GroupLayout.h>
|
||||
#include <GroupLayoutBuilder.h>
|
||||
#include <Alert.h>
|
||||
#include <Font.h>
|
||||
#include <Button.h>
|
||||
#include <StringView.h>
|
||||
#include <TextControl.h>
|
||||
#include <CheckBox.h>
|
||||
#include <String.h>
|
||||
#include <FindDirectory.h>
|
||||
#include <Node.h>
|
||||
#include <notification/Notifications.h>
|
||||
#include <Path.h>
|
||||
#include <File.h>
|
||||
#include <Directory.h>
|
||||
#include <VolumeRoster.h>
|
||||
#include <Volume.h>
|
||||
#include <Query.h>
|
||||
#include <SymLink.h>
|
||||
|
||||
#include "GeneralView.h"
|
||||
#include "SettingsHost.h"
|
||||
|
||||
#define _T(str) (str)
|
||||
|
||||
const int32 kServer = '_TSR';
|
||||
|
||||
const char* kStartServer = _T("Enable notifications");
|
||||
const char* kStopServer = _T("Disable notifications");
|
||||
const char* kStarted = _T("Events are notified");
|
||||
const char* kStopped = _T("Events are not notified");
|
||||
|
||||
|
||||
GeneralView::GeneralView(SettingsHost* host)
|
||||
:
|
||||
SettingsPane("general", host)
|
||||
{
|
||||
BFont statusFont;
|
||||
|
||||
// Set a smaller font for the status label
|
||||
statusFont.SetSize(be_plain_font->Size() * 0.8);
|
||||
|
||||
// Status button and label
|
||||
fServerButton = new BButton("server", kStartServer, new BMessage(kServer));
|
||||
fStatusLabel = new BStringView("status", kStopped);
|
||||
fStatusLabel->SetFont(&statusFont);
|
||||
|
||||
// Update status label and server button
|
||||
if (_IsServerRunning()) {
|
||||
fServerButton->SetLabel(kStopServer);
|
||||
fStatusLabel->SetText(kStarted);
|
||||
} else {
|
||||
fServerButton->SetLabel(kStartServer);
|
||||
fStatusLabel->SetText(kStopped);
|
||||
}
|
||||
|
||||
// Autostart
|
||||
fAutoStart = new BCheckBox("autostart",
|
||||
_T("Enable notifications at startup"), new BMessage(kSettingChanged));
|
||||
|
||||
// Display time
|
||||
fTimeout = new BTextControl(_T("Hide notifications from screen after"), NULL,
|
||||
new BMessage(kSettingChanged));
|
||||
BStringView* displayTimeLabel = new BStringView("dt_label",
|
||||
_T("seconds of inactivity"));
|
||||
|
||||
// Default position
|
||||
// TODO: Here will come a screen representation with the four corners clickable
|
||||
|
||||
// Load settings
|
||||
Load();
|
||||
|
||||
// Calculate inset
|
||||
float inset = ceilf(be_plain_font->Size() * 0.7f);
|
||||
|
||||
SetLayout(new BGroupLayout(B_VERTICAL));
|
||||
AddChild(BGroupLayoutBuilder(B_VERTICAL, inset)
|
||||
.AddGroup(B_HORIZONTAL, inset)
|
||||
.Add(fServerButton)
|
||||
.Add(fStatusLabel)
|
||||
.AddGlue()
|
||||
.End()
|
||||
|
||||
.AddGroup(B_VERTICAL, inset)
|
||||
.Add(fAutoStart)
|
||||
.AddGroup(B_HORIZONTAL)
|
||||
.AddGroup(B_HORIZONTAL, 2)
|
||||
.Add(fTimeout)
|
||||
.Add(displayTimeLabel)
|
||||
.End()
|
||||
.End()
|
||||
.End()
|
||||
|
||||
.AddGlue()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GeneralView::AttachedToWindow()
|
||||
{
|
||||
fServerButton->SetTarget(this);
|
||||
fAutoStart->SetTarget(this);
|
||||
fTimeout->SetTarget(this);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GeneralView::MessageReceived(BMessage* msg)
|
||||
{
|
||||
switch (msg->what) {
|
||||
case kServer: {
|
||||
entry_ref ref;
|
||||
|
||||
// Check if server is available
|
||||
if (!_CanFindServer(&ref)) {
|
||||
BAlert* alert = new BAlert(_T("Notifications"),
|
||||
_T("The notifications server cannot be found, "
|
||||
"this means your InfoPopper installation was not "
|
||||
"successfully completed."), _T("OK"), NULL,
|
||||
NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT);
|
||||
(void)alert->Go();
|
||||
return;
|
||||
}
|
||||
|
||||
if (_IsServerRunning()) {
|
||||
// Server team
|
||||
team_id team = be_roster->TeamFor(kNotificationServerSignature);
|
||||
|
||||
// Establish a connection to infopopper_server
|
||||
status_t ret = B_ERROR;
|
||||
BMessenger messenger(kNotificationServerSignature, team, &ret);
|
||||
if (ret != B_OK) {
|
||||
BAlert* alert = new BAlert(_T("Notifications"),
|
||||
_T("Notifications cannot be stopped, because "
|
||||
"the server can't be reached."),
|
||||
_T("OK"), NULL, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT);
|
||||
(void)alert->Go();
|
||||
return;
|
||||
}
|
||||
|
||||
// Send quit message
|
||||
if (messenger.SendMessage(new BMessage(B_QUIT_REQUESTED)) != B_OK) {
|
||||
BAlert* alert = new BAlert(_T("Notifications"),
|
||||
_T("Cannot disable notifications because the server "
|
||||
"can't be reached."), _T("OK"), NULL,
|
||||
NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT);
|
||||
(void)alert->Go();
|
||||
return;
|
||||
}
|
||||
|
||||
fServerButton->SetLabel(kStartServer);
|
||||
fStatusLabel->SetText(kStopped);
|
||||
} else {
|
||||
// Start server
|
||||
status_t err = be_roster->Launch(kNotificationServerSignature);
|
||||
if (err != B_OK) {
|
||||
BAlert* alert = new BAlert(_T("Notifications"),
|
||||
_T("Cannot enable notifications because the server "
|
||||
"cannot be found.\nThis means your InfoPopper "
|
||||
"installation was not successfully completed."),
|
||||
_T("OK"), NULL, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT);
|
||||
(void)alert->Go();
|
||||
return;
|
||||
}
|
||||
|
||||
fServerButton->SetLabel(kStopServer);
|
||||
fStatusLabel->SetText(kStarted);
|
||||
}
|
||||
} break;
|
||||
case kSettingChanged:
|
||||
SettingsPane::MessageReceived(msg);
|
||||
break;
|
||||
default:
|
||||
BView::MessageReceived(msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GeneralView::Load()
|
||||
{
|
||||
BPath path;
|
||||
|
||||
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
path.Append(kSettingsDirectory);
|
||||
|
||||
if (create_directory(path.Path(), 0755) != B_OK) {
|
||||
BAlert* alert = new BAlert("",
|
||||
_T("There was a problem saving the preferences.\n"
|
||||
"It's possible you don't have write access to the "
|
||||
"settings directory."), "OK", NULL, NULL,
|
||||
B_WIDTH_AS_USUAL, B_STOP_ALERT);
|
||||
(void)alert->Go();
|
||||
}
|
||||
|
||||
path.Append(kGeneralSettings);
|
||||
|
||||
BMessage settings;
|
||||
BFile file(path.Path(), B_READ_ONLY);
|
||||
settings.Unflatten(&file);
|
||||
|
||||
char buffer[255];
|
||||
|
||||
bool autoStart;
|
||||
if (settings.FindBool(kAutoStartName, &autoStart) != B_OK)
|
||||
autoStart = kDefaultAutoStart;
|
||||
fAutoStart->SetValue(autoStart ? B_CONTROL_ON : B_CONTROL_OFF);
|
||||
|
||||
int32 timeout;
|
||||
if (settings.FindInt32(kTimeoutName, &timeout) != B_OK)
|
||||
timeout = kDefaultTimeout;
|
||||
(void)sprintf(buffer, "%ld", timeout);
|
||||
fTimeout->SetText(buffer);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GeneralView::Save()
|
||||
{
|
||||
BPath path;
|
||||
|
||||
status_t ret = B_OK;
|
||||
ret = find_directory(B_USER_SETTINGS_DIRECTORY, &path);
|
||||
if (ret != B_OK)
|
||||
return ret;
|
||||
|
||||
path.Append(kSettingsDirectory);
|
||||
path.Append(kGeneralSettings);
|
||||
|
||||
BMessage settings;
|
||||
|
||||
bool autoStart = (fAutoStart->Value() == B_CONTROL_ON);
|
||||
settings.AddBool(kAutoStartName, autoStart);
|
||||
|
||||
int32 timeout = atol(fTimeout->Text());
|
||||
settings.AddInt32(kTimeoutName, timeout);
|
||||
|
||||
// Save settings file
|
||||
BFile file(path.Path(), B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
|
||||
ret = settings.Flatten(&file);
|
||||
if (ret != B_OK) {
|
||||
BAlert* alert = new BAlert("",
|
||||
_T("An error is occurred saving the preferences.\n"
|
||||
"It's possible you are running out of disk space."),
|
||||
"OK", NULL, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT);
|
||||
(void)alert->Go();
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Find server path
|
||||
entry_ref ref;
|
||||
if (!_CanFindServer(&ref)) {
|
||||
BAlert* alert = new BAlert("",
|
||||
_T("The notifications server cannot be found.\n"
|
||||
"A possible cause is an installation not done correctly"),
|
||||
"OK", NULL, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT);
|
||||
(void)alert->Go();
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
// UserBootscript command
|
||||
BPath serverPath(&ref);
|
||||
|
||||
// Start server at boot time
|
||||
ret = find_directory(B_USER_BOOT_DIRECTORY, &path, true);
|
||||
if (ret != B_OK) {
|
||||
BAlert* alert = new BAlert("",
|
||||
_T("Can't save preferences, you probably don't have write "
|
||||
"access to the boot settings directory."), "OK", NULL, NULL,
|
||||
B_WIDTH_AS_USUAL, B_STOP_ALERT);
|
||||
(void)alert->Go();
|
||||
return ret;
|
||||
}
|
||||
|
||||
path.Append("launch");
|
||||
BDirectory directory(path.Path());
|
||||
BEntry entry(&directory, serverPath.Leaf());
|
||||
|
||||
// Remove symbolic link
|
||||
entry.Remove();
|
||||
|
||||
if (autoStart) {
|
||||
// Put a symlink into ~/config/boot/launch
|
||||
if ((ret = directory.CreateSymLink(serverPath.Leaf(),
|
||||
serverPath.Path(), NULL) != B_OK)) {
|
||||
BAlert* alert = new BAlert("",
|
||||
_T("Can't enable notifications at startup time, you probably don't have "
|
||||
"write permission to the boot settings directory."), "OK", NULL, NULL,
|
||||
B_WIDTH_AS_USUAL, B_STOP_ALERT);
|
||||
(void)alert->Go();
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
GeneralView::Revert()
|
||||
{
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
GeneralView::_CanFindServer(entry_ref* ref)
|
||||
{
|
||||
// Try searching with be_roster
|
||||
if (be_roster->FindApp(kNotificationServerSignature, ref) == B_OK)
|
||||
return true;
|
||||
|
||||
// Try with a query and take the first result
|
||||
BVolumeRoster vroster;
|
||||
BVolume volume;
|
||||
char volName[B_FILE_NAME_LENGTH];
|
||||
|
||||
vroster.Rewind();
|
||||
|
||||
while (vroster.GetNextVolume(&volume) == B_OK) {
|
||||
if ((volume.InitCheck() != B_OK) || !volume.KnowsQuery())
|
||||
continue;
|
||||
|
||||
volume.GetName(volName);
|
||||
|
||||
BQuery *query = new BQuery();
|
||||
query->SetPredicate("(BEOS:APP_SIG==\""kNotificationServerSignature"\")");
|
||||
query->SetVolume(&volume);
|
||||
query->Fetch();
|
||||
|
||||
if (query->GetNextRef(ref) == B_OK)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
GeneralView::_IsServerRunning()
|
||||
{
|
||||
return be_roster->IsRunning(kNotificationServerSignature);
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2009, Pier Luigi Fiorini.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _GENERAL_VIEW_H
|
||||
#define _GENERAL_VIEW_H
|
||||
|
||||
#include "SettingsPane.h"
|
||||
|
||||
class BCheckBox;
|
||||
class BButton;
|
||||
class BStringView;
|
||||
class BTextControl;
|
||||
|
||||
class GeneralView : public SettingsPane {
|
||||
public:
|
||||
GeneralView(SettingsHost* host);
|
||||
|
||||
virtual void AttachedToWindow();
|
||||
virtual void MessageReceived(BMessage* msg);
|
||||
|
||||
// SettingsPane hooks
|
||||
status_t Load();
|
||||
status_t Save();
|
||||
status_t Revert();
|
||||
|
||||
private:
|
||||
BButton* fServerButton;
|
||||
BStringView* fStatusLabel;
|
||||
BCheckBox* fAutoStart;
|
||||
BTextControl* fTimeout;
|
||||
BCheckBox* fHideAll;
|
||||
|
||||
bool _CanFindServer(entry_ref* ref);
|
||||
bool _IsServerRunning();
|
||||
};
|
||||
|
||||
#endif // _GENERAL_VIEW_H
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2009, Pier Luigi Fiorini.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Pier Luigi Fiorini, pierluigi.fiorini@gmail.com
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <Bitmap.h>
|
||||
|
||||
#include "IconItem.h"
|
||||
#include "IconRule.h"
|
||||
|
||||
const int32 kEdgeOffset = 4;
|
||||
|
||||
|
||||
BIconItem::BIconItem(BView* owner, const char* label, BBitmap* icon)
|
||||
:
|
||||
fIcon(icon),
|
||||
fLabel(label),
|
||||
fSelected(false),
|
||||
fOwner(owner)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
BIconItem::~BIconItem()
|
||||
{
|
||||
delete fIcon;
|
||||
}
|
||||
|
||||
void BIconItem::Draw()
|
||||
{
|
||||
if (IsSelected()) {
|
||||
rgb_color color;
|
||||
rgb_color origHigh;
|
||||
|
||||
origHigh = fOwner->HighColor();
|
||||
|
||||
if (IsSelected())
|
||||
color = ui_color(B_CONTROL_HIGHLIGHT_COLOR);
|
||||
else
|
||||
color = fOwner->ViewColor();
|
||||
|
||||
fOwner->SetHighColor(color);
|
||||
fOwner->FillRect(fFrame);
|
||||
fOwner->SetHighColor(origHigh);
|
||||
}
|
||||
|
||||
if (fIcon)
|
||||
{
|
||||
fOwner->SetDrawingMode(B_OP_ALPHA);
|
||||
fOwner->DrawBitmap(fIcon, BPoint(fFrame.top + kEdgeOffset,
|
||||
fFrame.left + kEdgeOffset));
|
||||
fOwner->SetDrawingMode(B_OP_COPY);
|
||||
}
|
||||
|
||||
if (IsSelected())
|
||||
fOwner->SetDrawingMode(B_OP_OVER);
|
||||
|
||||
#if 0
|
||||
fOwner->MovePenTo(frame.left + kEdgeOffset + fIconWidth + kEdgeOffset,
|
||||
frame.bottom - fFontOffset);
|
||||
#else
|
||||
fOwner->MovePenTo(fFrame.left, fFrame.bottom - 10);
|
||||
#endif
|
||||
fOwner->SetHighColor(ui_color(B_CONTROL_TEXT_COLOR));
|
||||
fOwner->DrawString(" ");
|
||||
fOwner->DrawString(fLabel.String());
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
BIconItem::Label() const
|
||||
{
|
||||
return fLabel.String();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BIconItem::SetFrame(BRect frame)
|
||||
{
|
||||
fFrame = frame;
|
||||
}
|
||||
|
||||
|
||||
BRect
|
||||
BIconItem::Frame() const
|
||||
{
|
||||
return fFrame;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BIconItem::Select()
|
||||
{
|
||||
fSelected = true;
|
||||
Draw();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BIconItem::Deselect()
|
||||
{
|
||||
fSelected = false;
|
||||
Draw();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
BIconItem::IsSelected() const
|
||||
{
|
||||
return fSelected;
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2009, Pier Luigi Fiorini.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _ICON_ITEM_H
|
||||
#define _ICON_ITEM_H
|
||||
|
||||
#include <View.h>
|
||||
#include <String.h>
|
||||
|
||||
class BBitmap;
|
||||
|
||||
class BIconItem {
|
||||
public:
|
||||
BIconItem(BView* owner, const char* label, BBitmap* icon);
|
||||
virtual ~BIconItem();
|
||||
|
||||
void Draw();
|
||||
|
||||
const char* Label() const;
|
||||
|
||||
void SetFrame(BRect frame);
|
||||
BRect Frame() const;
|
||||
|
||||
void Select();
|
||||
void Deselect();
|
||||
bool IsSelected() const;
|
||||
|
||||
private:
|
||||
BString fLabel;
|
||||
BBitmap* fIcon;
|
||||
bool fSelected;
|
||||
BView* fOwner;
|
||||
BRect fFrame;
|
||||
};
|
||||
|
||||
#endif // _ICON_ITEM_H
|
|
@ -0,0 +1,270 @@
|
|||
/*
|
||||
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2009, Pier Luigi Fiorini.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Pier Luigi Fiorini, pierluigi.fiorini@gmail.com
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <Message.h>
|
||||
#include <Bitmap.h>
|
||||
#include <Window.h>
|
||||
#include <List.h>
|
||||
|
||||
#include "IconRule.h"
|
||||
#include "IconItem.h"
|
||||
|
||||
const int32 kEdgeOffset = 8;
|
||||
const int32 kBorderOffset = 1;
|
||||
|
||||
// TODO: Do we need to inherit from BControl?
|
||||
|
||||
BIconRule::BIconRule(const char* name)
|
||||
:
|
||||
BView(name, B_WILL_DRAW),
|
||||
fSelIndex(-1)
|
||||
{
|
||||
fIcons = new BList();
|
||||
}
|
||||
|
||||
|
||||
BIconRule::~BIconRule()
|
||||
{
|
||||
delete fIcons;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BIconRule::Invoke(BMessage* message)
|
||||
{
|
||||
bool notify = false;
|
||||
uint32 kind = InvokeKind(¬ify);
|
||||
|
||||
BMessage clone(kind);
|
||||
status_t err = B_BAD_VALUE;
|
||||
|
||||
if (!message && !notify)
|
||||
message = Message();
|
||||
|
||||
if (!message) {
|
||||
if (!IsWatched())
|
||||
return err;
|
||||
} else
|
||||
clone = *message;
|
||||
|
||||
clone.AddInt64("when", (int64)system_time());
|
||||
clone.AddPointer("source", this);
|
||||
clone.AddMessenger("be:sender", BMessenger(this));
|
||||
clone.AddInt32("index", fSelIndex);
|
||||
|
||||
if (message)
|
||||
err = BInvoker::Invoke(&clone);
|
||||
|
||||
SendNotices(kind, &clone);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BIconRule::AttachedToWindow()
|
||||
{
|
||||
BView::AttachedToWindow();
|
||||
|
||||
if (!Messenger().IsValid())
|
||||
SetTarget(Window(), NULL);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BIconRule::MouseDown(BPoint point)
|
||||
{
|
||||
if (!IsFocus()) {
|
||||
MakeFocus();
|
||||
Sync();
|
||||
Window()->UpdateIfNeeded();
|
||||
}
|
||||
|
||||
int32 index = IndexOf(point);
|
||||
if (index > -1)
|
||||
SlideToIcon(index);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BIconRule::Draw(BRect updateRect)
|
||||
{
|
||||
int32 count = CountIcons();
|
||||
if (count == 0)
|
||||
return;
|
||||
|
||||
rgb_color panelColor = ui_color(B_PANEL_BACKGROUND_COLOR);
|
||||
rgb_color lightColor = tint_color(panelColor, B_DARKEN_1_TINT);
|
||||
rgb_color darkColor = tint_color(lightColor, B_DARKEN_2_TINT);
|
||||
|
||||
SetHighColor(darkColor);
|
||||
StrokeLine(Bounds().LeftTop(), Bounds().RightTop());
|
||||
StrokeLine(Bounds().LeftTop(), Bounds().LeftBottom());
|
||||
|
||||
SetHighColor(lightColor);
|
||||
StrokeLine(Bounds().LeftBottom(), Bounds().RightBottom());
|
||||
StrokeLine(Bounds().RightTop(), Bounds().RightBottom());
|
||||
|
||||
BRect itemFrame(kEdgeOffset, kBorderOffset, -1, kBorderOffset + 64);
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
BIconItem* item = static_cast<BIconItem*>(fIcons->ItemAt(i));
|
||||
float width = StringWidth(item->Label()) + StringWidth(" ") * 2;
|
||||
if (width < 64.0f)
|
||||
width = 64.0f;
|
||||
itemFrame.right = itemFrame.left + width - 1;
|
||||
|
||||
if (itemFrame.Intersects(updateRect)) {
|
||||
item->SetFrame(itemFrame);
|
||||
item->Draw();
|
||||
}
|
||||
|
||||
itemFrame.left = itemFrame.right + kEdgeOffset + 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BMessage*
|
||||
BIconRule::SelectionMessage() const
|
||||
{
|
||||
return fMessage;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BIconRule::SetSelectionMessage(BMessage* message)
|
||||
{
|
||||
delete fMessage;
|
||||
fMessage = message;
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
BIconRule::AddIcon(const char* label, const BBitmap* icon)
|
||||
{
|
||||
BIconItem* item = new BIconItem(this, label, (BBitmap*)icon);
|
||||
if (CountIcons() == 0) {
|
||||
item->Select();
|
||||
fSelIndex = 0;
|
||||
}
|
||||
(void)fIcons->AddItem(item);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BIconRule::RemoveIconAt(int32 index)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BIconRule::RemoveAllIcons()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
BIconRule::CountIcons() const
|
||||
{
|
||||
return fIcons->CountItems();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BIconRule::SlideToIcon(int32 index)
|
||||
{
|
||||
// Ignore invalid items
|
||||
if ((index < 0) || (index > CountIcons() - 1))
|
||||
return;
|
||||
|
||||
BIconItem* item = static_cast<BIconItem*>(fIcons->ItemAt(index));
|
||||
if (item) {
|
||||
// Deselect previously selected item
|
||||
if (fSelIndex > -1) {
|
||||
BIconItem* selItem = static_cast<BIconItem*>(fIcons->ItemAt(fSelIndex));
|
||||
selItem->Deselect();
|
||||
}
|
||||
|
||||
// Select this item
|
||||
item->Select();
|
||||
fSelIndex = index;
|
||||
Invalidate();
|
||||
|
||||
// Invoke notification
|
||||
InvokeNotify(fMessage, B_CONTROL_MODIFIED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BIconRule::SlideToNext()
|
||||
{
|
||||
if (fSelIndex + 1 < CountIcons() - 1)
|
||||
return;
|
||||
SlideToIcon(fSelIndex + 1);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BIconRule::SlideToPrevious()
|
||||
{
|
||||
if (fSelIndex <= 0)
|
||||
return;
|
||||
SlideToIcon(fSelIndex - 1);
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
BIconRule::IndexOf(BPoint point)
|
||||
{
|
||||
int32 low = 0;
|
||||
int32 high = fIcons->CountItems() - 1;
|
||||
int32 mid = -1;
|
||||
float frameLeft = -1.0f;
|
||||
float frameRight = 1.0f;
|
||||
|
||||
// Binary search the list
|
||||
while (high >= low) {
|
||||
mid = (low + high) / 2;
|
||||
BIconItem* item = static_cast<BIconItem*>(fIcons->ItemAt(mid));
|
||||
frameLeft = item->Frame().left;
|
||||
frameRight = item->Frame().right;
|
||||
if (point.x < frameLeft)
|
||||
high = mid - 1;
|
||||
else if (point.x > frameRight)
|
||||
low = mid + 1;
|
||||
else
|
||||
return mid;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
BSize
|
||||
BIconRule::MinSize()
|
||||
{
|
||||
BSize minSize(BView::MinSize());
|
||||
minSize.height = 64 + (kBorderOffset * 2);
|
||||
return minSize;
|
||||
}
|
||||
|
||||
|
||||
BSize
|
||||
BIconRule::MaxSize()
|
||||
{
|
||||
return BView::MaxSize();
|
||||
}
|
||||
|
||||
|
||||
BSize
|
||||
BIconRule::PreferredSize()
|
||||
{
|
||||
return BView::PreferredSize();
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2009, Pier Luigi Fiorini.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _ICON_RULE_H
|
||||
#define _ICON_RULE_H
|
||||
|
||||
#include <Invoker.h>
|
||||
#include <View.h>
|
||||
|
||||
class BList;
|
||||
class BMessage;
|
||||
|
||||
class BIconRule : public BView, public BInvoker {
|
||||
public:
|
||||
BIconRule(const char* name);
|
||||
virtual ~BIconRule();
|
||||
|
||||
status_t Invoke(BMessage* message);
|
||||
|
||||
virtual void AttachedToWindow();
|
||||
|
||||
virtual void MouseDown(BPoint point);
|
||||
virtual void Draw(BRect updateRect);
|
||||
|
||||
BMessage* SelectionMessage() const;
|
||||
void SetSelectionMessage(BMessage* message);
|
||||
|
||||
int32 AddIcon(const char* label, const BBitmap* icon);
|
||||
void RemoveIconAt(int32 index);
|
||||
void RemoveAllIcons();
|
||||
|
||||
int32 CountIcons() const;
|
||||
|
||||
void SlideToIcon(int32 index);
|
||||
void SlideToNext();
|
||||
void SlideToPrevious();
|
||||
|
||||
int32 IndexOf(BPoint point);
|
||||
|
||||
virtual BSize MinSize();
|
||||
virtual BSize MaxSize();
|
||||
virtual BSize PreferredSize();
|
||||
|
||||
private:
|
||||
BList* fIcons;
|
||||
int32 fSelIndex;
|
||||
BMessage* fMessage;
|
||||
};
|
||||
|
||||
#endif // _ICON_RULE_H
|
|
@ -0,0 +1,20 @@
|
|||
SubDir HAIKU_TOP src preferences notifications ;
|
||||
|
||||
UsePrivateHeaders interface ;
|
||||
|
||||
Application Notifications :
|
||||
Notifications.cpp
|
||||
PrefletWin.cpp
|
||||
PrefletView.cpp
|
||||
SettingsPane.cpp
|
||||
GeneralView.cpp
|
||||
DisplayView.cpp
|
||||
NotificationsView.cpp
|
||||
IconRule.cpp
|
||||
IconItem.cpp
|
||||
: be translation libcolumnlistview.a libnotification.a $(TARGET_LIBSTDC++)
|
||||
: Notifications.rdef
|
||||
;
|
||||
|
||||
Depends Notifications : libcolumnlistview.a ;
|
||||
Depends Notifications : libnotification.a ;
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2009, Pier Luigi Fiorini.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Pier Luigi Fiorini, pierluigi.fiorini@gmail.com
|
||||
*/
|
||||
|
||||
#include <Application.h>
|
||||
|
||||
#include "PrefletWin.h"
|
||||
|
||||
class PrefletApp : public BApplication {
|
||||
public:
|
||||
PrefletApp();
|
||||
|
||||
virtual void ReadyToRun();
|
||||
virtual bool QuitRequested();
|
||||
|
||||
private:
|
||||
PrefletWin* fWindow;
|
||||
};
|
||||
|
||||
|
||||
PrefletApp::PrefletApp()
|
||||
:
|
||||
BApplication("application/x-vnd.Haiku-Notifications")
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PrefletApp::ReadyToRun()
|
||||
{
|
||||
fWindow = new PrefletWin;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PrefletApp::QuitRequested()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
PrefletApp app;
|
||||
app.Run();
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
|
||||
resource app_signature "application/x-vnd.Haiku-Notifications";
|
||||
|
||||
resource app_version {
|
||||
major = 1,
|
||||
middle = 0,
|
||||
minor = 0,
|
||||
|
||||
variety = B_APPV_ALPHA,
|
||||
internal = 0,
|
||||
|
||||
short_info = "Notifications",
|
||||
long_info = "Notifications ©2009 Pier Luigi Fiorini ©2010 Haiku"
|
||||
};
|
||||
|
||||
resource app_flags B_SINGLE_LAUNCH;
|
||||
|
||||
resource vector_icon {
|
||||
$"6E636966060401780501020106023A06C63967B3B838E138A51E4B2EAA46CD17"
|
||||
$"C3677F93FFFFFFFF02030603BF80A63DDD21BA0661BBABD34BDD9CC05D0900FF"
|
||||
$"DA8F3EFFAA008290600202030603BBE0A53C15CEB9A968B967964C2B2D459EFF"
|
||||
$"00FFDA8F29FFAA0054906002020106053CFCDB3CFBB1BB18EC3B1A2148FE2D4A"
|
||||
$"C91D89FFFFFFA8BAC6D1C3677F93E2BAC6D1FFFFFFFF040406FE034460C6E460"
|
||||
$"C4C6605460575C565E585A5E345E3460335D2E61305D2E4400054E244E24C5DB"
|
||||
$"B453C756B4915123C756B491562655255727C95329C95329592B592E592D592E"
|
||||
$"0616FFABAAAAAA0A4E244E24C5DBB453C756B4915123C756B491562655255727"
|
||||
$"C95329C95329592B592E592D592E4957475A425C3C5B365832552F532C50284C"
|
||||
$"264924462242213F203B2136233425330A1A4957475A425C3C5B365832552F53"
|
||||
$"2C50284C264924462242213F203B2136233425332C333135353738393F3F4344"
|
||||
$"4547484D4950070A000100000A01010130222201178822040A01010230222201"
|
||||
$"178400040A02010130222201178422040A0301022022220A0401032022220A05"
|
||||
$"0103123FBBD40000000000003FA51943DCFC44C1340117840004"
|
||||
};
|
|
@ -0,0 +1,273 @@
|
|||
/*
|
||||
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2009, Pier Luigi Fiorini.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Pier Luigi Fiorini, pierluigi.fiorini@gmail.com
|
||||
*/
|
||||
|
||||
#include <Alert.h>
|
||||
#include <Directory.h>
|
||||
#include <FindDirectory.h>
|
||||
#include <GroupLayout.h>
|
||||
#include <GroupLayoutBuilder.h>
|
||||
#include <Window.h>
|
||||
#include <CheckBox.h>
|
||||
#include <TextControl.h>
|
||||
#include <Path.h>
|
||||
#include <Notification.h>
|
||||
#include <notification/Notifications.h>
|
||||
#include <notification/NotificationReceived.h>
|
||||
|
||||
#include <ColumnListView.h>
|
||||
#include <ColumnTypes.h>
|
||||
|
||||
#include "NotificationsView.h"
|
||||
|
||||
#define _T(str) (str)
|
||||
|
||||
const float kEdgePadding = 5.0;
|
||||
const float kCLVTitlePadding = 8.0;
|
||||
|
||||
const int32 kApplicationSelected = '_ASL';
|
||||
const int32 kNotificationSelected = '_NSL';
|
||||
|
||||
const int32 kCLVDeleteRow = 'av02';
|
||||
|
||||
// Applications column indexes
|
||||
const int32 kAppIndex = 0;
|
||||
const int32 kAppEnabledIndex = 1;
|
||||
|
||||
// Notifications column indexes
|
||||
const int32 kTitleIndex = 0;
|
||||
const int32 kDateIndex = 1;
|
||||
const int32 kTypeIndex = 2;
|
||||
const int32 kAllowIndex = 3;
|
||||
|
||||
const int32 kSettingChanged = '_STC';
|
||||
|
||||
|
||||
NotificationsView::NotificationsView()
|
||||
:
|
||||
BView("apps", B_WILL_DRAW)
|
||||
{
|
||||
BRect rect(0, 0, 100, 100);
|
||||
|
||||
// Search application field
|
||||
fSearch = new BTextControl(_T("Search:"), NULL,
|
||||
new BMessage(kSettingChanged));
|
||||
|
||||
// Applications list
|
||||
fApplications = new BColumnListView(rect, _T("Applications"),
|
||||
0, B_WILL_DRAW, B_FANCY_BORDER, true);
|
||||
fApplications->SetSelectionMode(B_SINGLE_SELECTION_LIST);
|
||||
|
||||
fAppCol = new BStringColumn(_T("Application"), 200,
|
||||
be_plain_font->StringWidth(_T("Application")) + (kCLVTitlePadding * 2),
|
||||
rect.Width(), B_TRUNCATE_END, B_ALIGN_LEFT);
|
||||
fApplications->AddColumn(fAppCol, kAppIndex);
|
||||
|
||||
fAppEnabledCol = new BStringColumn(_T("Enabled"), 10,
|
||||
be_plain_font->StringWidth(_T("Enabled")) + (kCLVTitlePadding * 2),
|
||||
rect.Width(), B_TRUNCATE_END, B_ALIGN_LEFT);
|
||||
fApplications->AddColumn(fAppEnabledCol, kAppEnabledIndex);
|
||||
|
||||
// Notifications list
|
||||
fNotifications = new BColumnListView(rect, _T("Notifications"),
|
||||
0, B_WILL_DRAW, B_FANCY_BORDER, true);
|
||||
fNotifications->SetSelectionMode(B_SINGLE_SELECTION_LIST);
|
||||
|
||||
fTitleCol = new BStringColumn(_T("Title"), 100,
|
||||
be_plain_font->StringWidth(_T("Title")) + (kCLVTitlePadding * 2),
|
||||
rect.Width(), B_TRUNCATE_END, B_ALIGN_LEFT);
|
||||
fNotifications->AddColumn(fTitleCol, kTitleIndex);
|
||||
|
||||
fDateCol = new BDateColumn(_T("Last Received"), 100,
|
||||
be_plain_font->StringWidth(_T("Last Received")) + (kCLVTitlePadding * 2),
|
||||
rect.Width(), B_ALIGN_LEFT);
|
||||
fNotifications->AddColumn(fDateCol, kDateIndex);
|
||||
|
||||
fTypeCol = new BStringColumn(_T("Type"), 100,
|
||||
be_plain_font->StringWidth(_T("Type")) + (kCLVTitlePadding * 2),
|
||||
rect.Width(), B_TRUNCATE_END, B_ALIGN_LEFT);
|
||||
fNotifications->AddColumn(fTypeCol, kTypeIndex);
|
||||
|
||||
fAllowCol = new BStringColumn(_T("Allowed"), 100,
|
||||
be_plain_font->StringWidth(_T("Allowed")) + (kCLVTitlePadding * 2),
|
||||
rect.Width(), B_TRUNCATE_END, B_ALIGN_LEFT);
|
||||
fNotifications->AddColumn(fAllowCol, kAllowIndex);
|
||||
|
||||
// Load the applications list
|
||||
_LoadAppUsage();
|
||||
_PopulateApplications();
|
||||
|
||||
// Calculate inset
|
||||
float inset = ceilf(be_plain_font->Size() * 0.7f);
|
||||
|
||||
// Set layout
|
||||
SetLayout(new BGroupLayout(B_VERTICAL));
|
||||
|
||||
// Add views
|
||||
AddChild(BGroupLayoutBuilder(B_VERTICAL, inset)
|
||||
.AddGroup(B_HORIZONTAL)
|
||||
.AddGlue()
|
||||
.Add(fSearch)
|
||||
.End()
|
||||
.Add(fApplications)
|
||||
.Add(fNotifications)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NotificationsView::AttachedToWindow()
|
||||
{
|
||||
fApplications->SetTarget(this);
|
||||
fApplications->SetInvocationMessage(new BMessage(kApplicationSelected));
|
||||
|
||||
fNotifications->SetTarget(this);
|
||||
fNotifications->SetInvocationMessage(new BMessage(kNotificationSelected));
|
||||
|
||||
#if 0
|
||||
fNotifications->AddFilter(new BMessageFilter(B_ANY_DELIVERY,
|
||||
B_ANY_SOURCE, B_KEY_DOWN, CatchDelete));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NotificationsView::MessageReceived(BMessage* msg)
|
||||
{
|
||||
switch (msg->what) {
|
||||
case kApplicationSelected: {
|
||||
BRow *row = fApplications->CurrentSelection();
|
||||
if (row == NULL)
|
||||
return;
|
||||
BStringField* appname =
|
||||
dynamic_cast<BStringField*>(row->GetField(kAppIndex));
|
||||
|
||||
appusage_t::iterator it = fAppFilters.find(appname->String());
|
||||
if (it != fAppFilters.end())
|
||||
_Populate(it->second);
|
||||
} break;
|
||||
case kNotificationSelected:
|
||||
break;
|
||||
default:
|
||||
BView::MessageReceived(msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
NotificationsView::_LoadAppUsage()
|
||||
{
|
||||
BPath path;
|
||||
|
||||
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
path.Append(kSettingsDirectory);
|
||||
|
||||
if (create_directory(path.Path(), 0755) != B_OK) {
|
||||
BAlert* alert = new BAlert("",
|
||||
_T("There was a problem saving the preferences.\n"
|
||||
"It's possible you don't have write access to the "
|
||||
"settings directory."), "OK", NULL, NULL,
|
||||
B_WIDTH_AS_USUAL, B_STOP_ALERT);
|
||||
(void)alert->Go();
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
path.Append(kFiltersSettings);
|
||||
|
||||
BFile file(path.Path(), B_READ_ONLY);
|
||||
BMessage settings;
|
||||
if (settings.Unflatten(&file) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
type_code type;
|
||||
int32 count = 0;
|
||||
|
||||
if (settings.GetInfo("app_usage", &type, &count) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
// Clean filters
|
||||
appusage_t::iterator auIt;
|
||||
for (auIt = fAppFilters.begin(); auIt != fAppFilters.end(); auIt++)
|
||||
delete auIt->second;
|
||||
fAppFilters.clear();
|
||||
|
||||
// Add new filters
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
AppUsage* app = new AppUsage();
|
||||
settings.FindFlat("app_usage", i, app);
|
||||
fAppFilters[app->Name()] = app;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NotificationsView::_PopulateApplications()
|
||||
{
|
||||
appusage_t::iterator it;
|
||||
|
||||
fApplications->Clear();
|
||||
|
||||
for (it = fAppFilters.begin(); it != fAppFilters.end(); ++it) {
|
||||
BRow* row = new BRow();
|
||||
row->SetField(new BStringField(it->first.String()), kAppIndex);
|
||||
fApplications->AddRow(row);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NotificationsView::_Populate(AppUsage* usage)
|
||||
{
|
||||
// Sanity check
|
||||
if (!usage)
|
||||
return;
|
||||
|
||||
int32 size = usage->Notifications();
|
||||
|
||||
if (usage->Allowed() == false)
|
||||
fBlockAll->SetValue(B_CONTROL_ON);
|
||||
|
||||
fNotifications->Clear();
|
||||
|
||||
for (int32 i = 0; i < size; i++) {
|
||||
NotificationReceived* notification = usage->NotificationAt(i);
|
||||
time_t updated = notification->LastReceived();
|
||||
const char* allow = notification->Allowed() ? _T("Yes") : _T("No");
|
||||
const char* type = "";
|
||||
|
||||
switch (notification->Type()) {
|
||||
case B_INFORMATION_NOTIFICATION:
|
||||
type = _T("Information");
|
||||
break;
|
||||
case B_IMPORTANT_NOTIFICATION:
|
||||
type = _T("Important");
|
||||
break;
|
||||
case B_ERROR_NOTIFICATION:
|
||||
type = _T("Error");
|
||||
break;
|
||||
case B_PROGRESS_NOTIFICATION:
|
||||
type = _T("Progress");
|
||||
break;
|
||||
default:
|
||||
type = _T("Unknown");
|
||||
}
|
||||
|
||||
BRow* row = new BRow();
|
||||
row->SetField(new BStringField(notification->Title()), kTitleIndex);
|
||||
row->SetField(new BDateField(&updated), kDateIndex);
|
||||
row->SetField(new BStringField(type), kTypeIndex);
|
||||
row->SetField(new BStringField(allow), kAllowIndex);
|
||||
|
||||
fNotifications->AddRow(row);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2009, Pier Luigi Fiorini.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _APPS_VIEW_H
|
||||
#define _APPS_VIEW_H
|
||||
|
||||
#include <View.h>
|
||||
|
||||
#include <notification/AppUsage.h>
|
||||
|
||||
typedef std::map<BString, AppUsage *> appusage_t;
|
||||
|
||||
class BCheckBox;
|
||||
class BTextControl;
|
||||
class BColumnListView;
|
||||
class BStringColumn;
|
||||
class BDateColumn;
|
||||
|
||||
class NotificationsView : public BView {
|
||||
public:
|
||||
NotificationsView();
|
||||
|
||||
virtual void AttachedToWindow();
|
||||
virtual void MessageReceived(BMessage* msg);
|
||||
|
||||
private:
|
||||
status_t _LoadAppUsage();
|
||||
void _PopulateApplications();
|
||||
void _Populate(AppUsage* usage);
|
||||
|
||||
appusage_t fAppFilters;
|
||||
BCheckBox* fBlockAll;
|
||||
BTextControl* fSearch;
|
||||
BColumnListView* fApplications;
|
||||
BStringColumn* fAppCol;
|
||||
BStringColumn* fAppEnabledCol;
|
||||
BColumnListView* fNotifications;
|
||||
BStringColumn* fTitleCol;
|
||||
BDateColumn* fDateCol;
|
||||
BStringColumn* fTypeCol;
|
||||
BStringColumn* fAllowCol;
|
||||
};
|
||||
|
||||
#endif // _APPS_VIEW_H
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2009, Pier Luigi Fiorini.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Pier Luigi Fiorini, pierluigi.fiorini@gmail.com
|
||||
*/
|
||||
|
||||
#include <Message.h>
|
||||
#include <GroupLayout.h>
|
||||
#include <GroupLayoutBuilder.h>
|
||||
#include <CardLayout.h>
|
||||
#include <LayoutItem.h>
|
||||
|
||||
#include "SettingsHost.h"
|
||||
#include "PrefletView.h"
|
||||
#include "IconRule.h"
|
||||
#include "GeneralView.h"
|
||||
#include "DisplayView.h"
|
||||
#include "NotificationsView.h"
|
||||
|
||||
#define _T(str) (str)
|
||||
|
||||
const int32 kPageSelected = '_LCH';
|
||||
|
||||
|
||||
PrefletView::PrefletView(SettingsHost* host)
|
||||
:
|
||||
BView("pages", B_WILL_DRAW)
|
||||
{
|
||||
// Page selector
|
||||
fRule = new BIconRule("icon_rule");
|
||||
fRule->SetSelectionMessage(new BMessage(kPageSelected));
|
||||
(void)fRule->AddIcon(_T("General"), NULL);
|
||||
(void)fRule->AddIcon(_T("Display"), NULL);
|
||||
//(void)fRule->AddIcon(_T("Notifications"), NULL);
|
||||
|
||||
// View for card layout
|
||||
fPagesView = new BView("pages", B_WILL_DRAW);
|
||||
|
||||
// Pages
|
||||
GeneralView* general = new GeneralView(host);
|
||||
DisplayView* display = new DisplayView(host);
|
||||
NotificationsView* apps = new NotificationsView();
|
||||
|
||||
// Calculate inset
|
||||
float inset = ceilf(be_plain_font->Size() * 0.7f);
|
||||
|
||||
// Build the layout
|
||||
SetLayout(new BGroupLayout(B_VERTICAL));
|
||||
|
||||
// Card layout for pages
|
||||
BCardLayout* layout = new BCardLayout();
|
||||
fPagesView->SetLayout(layout);
|
||||
layout->AddView(general);
|
||||
layout->AddView(display);
|
||||
layout->AddView(apps);
|
||||
|
||||
// Add childs
|
||||
AddChild(BGroupLayoutBuilder(B_VERTICAL, inset)
|
||||
.Add(fRule)
|
||||
.Add(fPagesView)
|
||||
);
|
||||
|
||||
// Select the first view
|
||||
Select(0);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PrefletView::AttachedToWindow()
|
||||
{
|
||||
fRule->SetTarget(this);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PrefletView::MessageReceived(BMessage* message)
|
||||
{
|
||||
switch (message->what) {
|
||||
case kPageSelected:
|
||||
{
|
||||
int32 index = B_ERROR;
|
||||
if (message->FindInt32("index", &index) != B_OK)
|
||||
return;
|
||||
|
||||
Select(index);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BView::MessageReceived(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PrefletView::Select(int32 index)
|
||||
{
|
||||
BCardLayout* layout
|
||||
= dynamic_cast<BCardLayout*>(fPagesView->GetLayout());
|
||||
if (layout)
|
||||
layout->SetVisibleItem(index);
|
||||
}
|
||||
|
||||
|
||||
BView*
|
||||
PrefletView::CurrentPage()
|
||||
{
|
||||
BCardLayout* layout
|
||||
= dynamic_cast<BCardLayout*>(fPagesView->GetLayout());
|
||||
if (layout)
|
||||
return layout->VisibleItem()->View();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
PrefletView::CountPages() const
|
||||
{
|
||||
BCardLayout* layout
|
||||
= dynamic_cast<BCardLayout*>(fPagesView->GetLayout());
|
||||
if (layout)
|
||||
return layout->CountItems();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
BView*
|
||||
PrefletView::PageAt(int32 index)
|
||||
{
|
||||
BCardLayout* layout
|
||||
= dynamic_cast<BCardLayout*>(fPagesView->GetLayout());
|
||||
if (layout)
|
||||
return layout->ItemAt(index)->View();
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2009, Pier Luigi Fiorini.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _PREFLET_VIEW_H
|
||||
#define _PREFLET_VIEW_H
|
||||
|
||||
#include <View.h>
|
||||
|
||||
class BIconRule;
|
||||
|
||||
class SettingsHost;
|
||||
|
||||
class PrefletView : public BView {
|
||||
public:
|
||||
PrefletView(SettingsHost* host);
|
||||
|
||||
virtual void AttachedToWindow();
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
|
||||
void Select(int32 index);
|
||||
BView* CurrentPage();
|
||||
int32 CountPages() const;
|
||||
BView* PageAt(int32 index);
|
||||
|
||||
private:
|
||||
BIconRule* fRule;
|
||||
BView* fPagesView;
|
||||
};
|
||||
|
||||
#endif // PREFLETVIEW_H
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2009, Pier Luigi Fiorini.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Pier Luigi Fiorini, pierluigi.fiorini@gmail.com
|
||||
*/
|
||||
|
||||
#include <Application.h>
|
||||
#include <GroupLayout.h>
|
||||
#include <GroupLayoutBuilder.h>
|
||||
#include <Button.h>
|
||||
|
||||
#include "PrefletWin.h"
|
||||
#include "PrefletView.h"
|
||||
|
||||
#define _T(str) (str)
|
||||
|
||||
const int32 kRevert = '_RVT';
|
||||
const int32 kSave = '_SAV';
|
||||
|
||||
|
||||
PrefletWin::PrefletWin()
|
||||
:
|
||||
BWindow(BRect(0, 0, 1, 1), "Notifications", B_TITLED_WINDOW, B_NOT_ZOOMABLE
|
||||
| B_NOT_RESIZABLE | B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS)
|
||||
{
|
||||
// Preflet container view
|
||||
fMainView = new PrefletView(this);
|
||||
|
||||
// Save and revert buttons
|
||||
fRevert = new BButton("revert", _T("Revert"), new BMessage(kRevert));
|
||||
fRevert->SetEnabled(false);
|
||||
fSave = new BButton("save", _T("Save"), new BMessage(kSave));
|
||||
fSave->SetEnabled(false);
|
||||
|
||||
// Calculate inset
|
||||
float inset = ceilf(be_plain_font->Size() * 0.7f);
|
||||
|
||||
// Build the layout
|
||||
SetLayout(new BGroupLayout(B_VERTICAL));
|
||||
|
||||
// Add childs
|
||||
AddChild(BGroupLayoutBuilder(B_VERTICAL, inset)
|
||||
.Add(fMainView)
|
||||
|
||||
.AddGroup(B_HORIZONTAL, inset)
|
||||
.AddGlue()
|
||||
.Add(fRevert)
|
||||
.Add(fSave)
|
||||
.End()
|
||||
|
||||
.SetInsets(inset, inset, inset, inset)
|
||||
);
|
||||
|
||||
// Center this window on screen and show it
|
||||
CenterOnScreen();
|
||||
Show();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PrefletWin::MessageReceived(BMessage* msg)
|
||||
{
|
||||
switch (msg->what) {
|
||||
case kSave:
|
||||
for (int32 i = 0; i < fMainView->CountPages(); i++) {
|
||||
SettingsPane* pane =
|
||||
dynamic_cast<SettingsPane*>(fMainView->PageAt(i));
|
||||
if (pane) {
|
||||
if (pane->Save() == B_OK) {
|
||||
fSave->SetEnabled(false);
|
||||
fRevert->SetEnabled(true);
|
||||
} else
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case kRevert:
|
||||
for (int32 i = 0; i < fMainView->CountPages(); i++) {
|
||||
SettingsPane* pane =
|
||||
dynamic_cast<SettingsPane*>(fMainView->PageAt(i));
|
||||
if (pane) {
|
||||
if (pane->Revert() == B_OK)
|
||||
fRevert->SetEnabled(false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
BWindow::MessageReceived(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
PrefletWin::QuitRequested()
|
||||
{
|
||||
be_app_messenger.SendMessage(B_QUIT_REQUESTED);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PrefletWin::SettingChanged()
|
||||
{
|
||||
fSave->SetEnabled(true);
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2009, Pier Luigi Fiorini.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _PREFLET_WIN_H
|
||||
#define _PREFLET_WIN_H
|
||||
|
||||
#include <Window.h>
|
||||
|
||||
#include "SettingsHost.h"
|
||||
|
||||
class BButton;
|
||||
|
||||
class PrefletView;
|
||||
|
||||
class PrefletWin : public BWindow, public SettingsHost {
|
||||
public:
|
||||
PrefletWin();
|
||||
|
||||
virtual bool QuitRequested();
|
||||
virtual void MessageReceived(BMessage* msg);
|
||||
|
||||
virtual void SettingChanged();
|
||||
|
||||
private:
|
||||
PrefletView* fMainView;
|
||||
BButton* fSave;
|
||||
BButton* fRevert;
|
||||
};
|
||||
|
||||
#endif // _PREFLET_WIN_H
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2009, Pier Luigi Fiorini.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _SETTINGS_HOST_H
|
||||
#define _SETTINGS_HOST_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "SettingsPane.h"
|
||||
|
||||
class SettingsHost {
|
||||
public:
|
||||
SettingsHost() {}
|
||||
|
||||
virtual void SettingChanged() = 0;
|
||||
};
|
||||
|
||||
#endif // _SETTINGS_HOST_H
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2009, Pier Luigi Fiorini.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Pier Luigi Fiorini, pierluigi.fiorini@gmail.com
|
||||
*/
|
||||
|
||||
#include <Message.h>
|
||||
#include <Node.h>
|
||||
#include <Path.h>
|
||||
#include <FindDirectory.h>
|
||||
#include <Directory.h>
|
||||
|
||||
#include "SettingsPane.h"
|
||||
#include "SettingsHost.h"
|
||||
|
||||
|
||||
SettingsPane::SettingsPane(const char* name, SettingsHost* host)
|
||||
:
|
||||
BView(name, B_WILL_DRAW),
|
||||
fHost(host)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SettingsPane::MessageReceived(BMessage* msg)
|
||||
{
|
||||
switch (msg->what) {
|
||||
case kSettingChanged:
|
||||
fHost->SettingChanged();
|
||||
break;
|
||||
default:
|
||||
BView::MessageReceived(msg);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2009, Pier Luigi Fiorini.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _SETTINGS_PANE_H
|
||||
#define _SETTINGS_PANE_H
|
||||
|
||||
#include <View.h>
|
||||
|
||||
class BNode;
|
||||
|
||||
class SettingsHost;
|
||||
|
||||
const int32 kSettingChanged = '_STC';
|
||||
|
||||
class SettingsPane : public BView {
|
||||
public:
|
||||
SettingsPane(const char* name, SettingsHost* host);
|
||||
|
||||
virtual void MessageReceived(BMessage* msg);
|
||||
|
||||
virtual status_t Load() = 0;
|
||||
virtual status_t Save() = 0;
|
||||
virtual status_t Revert() = 0;
|
||||
|
||||
protected:
|
||||
SettingsHost* fHost;
|
||||
};
|
||||
|
||||
#endif // _SETTINGS_PANE_H
|
|
@ -11,6 +11,7 @@ SubInclude HAIKU_TOP src servers media_addon ;
|
|||
SubInclude HAIKU_TOP src servers midi ;
|
||||
SubInclude HAIKU_TOP src servers mount ;
|
||||
SubInclude HAIKU_TOP src servers net ;
|
||||
SubInclude HAIKU_TOP src servers notification ;
|
||||
SubInclude HAIKU_TOP src servers power ;
|
||||
SubInclude HAIKU_TOP src servers print ;
|
||||
SubInclude HAIKU_TOP src servers registrar ;
|
||||
|
|
|
@ -0,0 +1,366 @@
|
|||
/*
|
||||
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2008-2009, Pier Luigi Fiorini. All Rights Reserved.
|
||||
* Copyright 2004-2008, Michael Davidson. All Rights Reserved.
|
||||
* Copyright 2004-2007, Mikael Eiman. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Michael Davidson, slaad@bong.com.au
|
||||
* Mikael Eiman, mikael@eiman.tv
|
||||
* Pier Luigi Fiorini, pierluigi.fiorini@gmail.com
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "AppGroupView.h"
|
||||
|
||||
#include "NotificationWindow.h"
|
||||
#include "NotificationView.h"
|
||||
|
||||
|
||||
AppGroupView::AppGroupView(NotificationWindow* win, const char* label)
|
||||
:
|
||||
BView(BRect(0, 0, win->ViewWidth(), 1), label, B_FOLLOW_LEFT_RIGHT,
|
||||
B_WILL_DRAW|B_FULL_UPDATE_ON_RESIZE|B_FRAME_EVENTS),
|
||||
fLabel(label),
|
||||
fParent(win),
|
||||
fCollapsed(false)
|
||||
{
|
||||
Show();
|
||||
}
|
||||
|
||||
|
||||
AppGroupView::~AppGroupView()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AppGroupView::AttachedToWindow()
|
||||
{
|
||||
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
SetHighColor(ui_color(B_PANEL_TEXT_COLOR));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AppGroupView::Draw(BRect updateRect)
|
||||
{
|
||||
FillRect(Bounds(), B_SOLID_LOW);
|
||||
|
||||
BString label = fLabel;
|
||||
if (fCollapsed)
|
||||
label << " (" << fInfo.size() << ")";
|
||||
|
||||
font_height fh;
|
||||
be_bold_font->GetHeight(&fh);
|
||||
float labelOffset = fh.ascent + fh.leading;
|
||||
|
||||
BRect borderRect = Bounds().InsetByCopy(kEdgePadding, kEdgePadding);
|
||||
borderRect.top = labelOffset;
|
||||
|
||||
BRect textRect = borderRect;
|
||||
textRect.left = kEdgePadding * 2;
|
||||
textRect.right = textRect.left + be_bold_font->StringWidth(label.String())
|
||||
+ (kEdgePadding * 3);
|
||||
textRect.bottom = labelOffset;
|
||||
|
||||
BRect closeCross = fCloseRect;
|
||||
closeCross.InsetBy(kSmallPadding, kSmallPadding);
|
||||
|
||||
rgb_color detailCol = ui_color(B_CONTROL_BORDER_COLOR);
|
||||
detailCol = tint_color(detailCol, B_LIGHTEN_2_TINT);
|
||||
// detailCol = tint_color(detailCol, B_LIGHTEN_1_TINT);
|
||||
|
||||
if (fCollapsed) {
|
||||
PushState();
|
||||
SetFont(be_bold_font);
|
||||
SetPenSize(kPenSize);
|
||||
float linePos = textRect.top + textRect.Height() / 2;
|
||||
|
||||
// Draw the line to the expand widget
|
||||
PushState();
|
||||
SetHighColor(detailCol);
|
||||
StrokeLine(BPoint(kEdgePadding, linePos), BPoint(fCollapseRect.left, linePos));
|
||||
PopState();
|
||||
|
||||
// Draw the expand widget
|
||||
PushState();
|
||||
SetHighColor(detailCol);
|
||||
StrokeRoundRect(fCollapseRect, kSmallPadding, kSmallPadding);
|
||||
|
||||
BPoint expandHorStart(fCollapseRect.left + kSmallPadding, fCollapseRect.Height() / 2 + fCollapseRect.top);
|
||||
BPoint expandHorEnd(fCollapseRect.right - kSmallPadding, fCollapseRect.Height() / 2 + fCollapseRect.top);
|
||||
StrokeLine(expandHorStart, expandHorEnd);
|
||||
|
||||
BPoint expandVerStart(fCollapseRect.Width() / 2 + fCollapseRect.left, fCollapseRect.top + kSmallPadding);
|
||||
BPoint expandVerEnd(fCollapseRect.Width() / 2 + fCollapseRect.left, fCollapseRect.bottom - kSmallPadding);
|
||||
StrokeLine(expandVerStart, expandVerEnd);
|
||||
PopState();
|
||||
|
||||
// Draw the app title
|
||||
DrawString(label.String(), BPoint(fCollapseRect.right + kEdgePadding, labelOffset + kEdgePadding));
|
||||
|
||||
// Draw the line from the label to the close widget
|
||||
PushState();
|
||||
SetHighColor(detailCol);
|
||||
|
||||
BPoint lineSeg2Start(textRect.right + kSmallPadding / 2, linePos);
|
||||
BPoint lineSeg2End(fCloseRect.left, linePos);
|
||||
StrokeLine(lineSeg2Start, lineSeg2End);
|
||||
PopState();
|
||||
|
||||
// Draw the dismiss widget
|
||||
PushState();
|
||||
SetHighColor(detailCol);
|
||||
|
||||
StrokeRoundRect(fCloseRect, kSmallPadding, kSmallPadding);
|
||||
|
||||
StrokeLine(closeCross.LeftTop(), closeCross.RightBottom());
|
||||
StrokeLine(closeCross.RightTop(), closeCross.LeftBottom());
|
||||
PopState();
|
||||
|
||||
// Draw the line from the dismiss widget
|
||||
PushState();
|
||||
SetHighColor(detailCol);
|
||||
|
||||
BPoint lineSeg3Start(fCloseRect.right, linePos);
|
||||
BPoint lineSeg3End(borderRect.right, linePos);
|
||||
StrokeLine(lineSeg3Start, lineSeg3End);
|
||||
PopState();
|
||||
|
||||
PopState();
|
||||
} else {
|
||||
PushState();
|
||||
SetFont(be_bold_font);
|
||||
SetPenSize(kPenSize);
|
||||
|
||||
// Draw the border
|
||||
PushState();
|
||||
SetHighColor(detailCol);
|
||||
// StrokeRoundRect(borderRect, kEdgePadding, kEdgePadding * 2);
|
||||
StrokeRect(borderRect);
|
||||
PopState();
|
||||
|
||||
FillRect(textRect, B_SOLID_LOW);
|
||||
|
||||
// Draw the collapse widget
|
||||
PushState();
|
||||
SetHighColor(detailCol);
|
||||
StrokeRoundRect(fCollapseRect, kSmallPadding, kSmallPadding);
|
||||
|
||||
BPoint expandHorStart(fCollapseRect.left + kSmallPadding, fCollapseRect.Height() / 2 + fCollapseRect.top);
|
||||
BPoint expandHorEnd(fCollapseRect.right - kSmallPadding, fCollapseRect.Height() / 2 + fCollapseRect.top);
|
||||
|
||||
StrokeLine(expandHorStart, expandHorEnd);
|
||||
PopState();
|
||||
|
||||
// Draw the dismiss widget
|
||||
PushState();
|
||||
SetHighColor(detailCol);
|
||||
FillRect(fCloseRect, B_SOLID_LOW);
|
||||
|
||||
StrokeRoundRect(fCloseRect, kSmallPadding, kSmallPadding);
|
||||
|
||||
StrokeLine(closeCross.LeftTop(), closeCross.RightBottom());
|
||||
StrokeLine(closeCross.RightTop(), closeCross.LeftBottom());
|
||||
PopState();
|
||||
|
||||
// Draw the label
|
||||
DrawString(label.String(), BPoint(fCollapseRect.right + kEdgePadding, labelOffset + kEdgePadding));
|
||||
PopState();
|
||||
}
|
||||
|
||||
Sync();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AppGroupView::MouseDown(BPoint point)
|
||||
{
|
||||
bool changed = false;
|
||||
if (fCloseRect.Contains(point)) {
|
||||
changed = true;
|
||||
|
||||
int32 children = fInfo.size();
|
||||
for (int32 i = 0; i < children; i++) {
|
||||
fInfo[i]->RemoveSelf();
|
||||
delete fInfo[i];
|
||||
}
|
||||
fInfo.clear();
|
||||
}
|
||||
|
||||
if (fCollapseRect.Contains(point)) {
|
||||
fCollapsed = !fCollapsed;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
ResizeViews();
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AppGroupView::GetPreferredSize(float* width, float* height)
|
||||
{
|
||||
font_height fh;
|
||||
be_bold_font->GetHeight(&fh);
|
||||
|
||||
float h = fh.ascent + fh.leading + fh.leading;
|
||||
h += kEdgePadding * 2; // Padding between top and bottom of label
|
||||
|
||||
if (!fCollapsed) {
|
||||
int32 children = fInfo.size();
|
||||
|
||||
for (int32 i = 0; i < children; i++) {
|
||||
float childHeight = 0;
|
||||
float childWidth = 0;
|
||||
|
||||
fInfo[i]->GetPreferredSize(&childWidth, &childHeight);
|
||||
|
||||
h += childHeight;
|
||||
}
|
||||
}
|
||||
|
||||
h += kEdgePadding;
|
||||
|
||||
*width = fParent->ViewWidth();
|
||||
*height = h;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AppGroupView::MessageReceived(BMessage* msg)
|
||||
{
|
||||
switch (msg->what) {
|
||||
case kRemoveView:
|
||||
{
|
||||
NotificationView* view = NULL;
|
||||
if (msg->FindPointer("view", (void**)&view) != B_OK)
|
||||
return;
|
||||
|
||||
infoview_t::iterator vIt = find(fInfo.begin(), fInfo.end(), view);
|
||||
|
||||
if (vIt != fInfo.end()) {
|
||||
fInfo.erase(vIt);
|
||||
view->RemoveSelf();
|
||||
delete view;
|
||||
}
|
||||
|
||||
ResizeViews();
|
||||
Invalidate();
|
||||
|
||||
// When all the views are destroy, save app filters
|
||||
if (fInfo.size() == 0)
|
||||
dynamic_cast<NotificationWindow*>(Window())->SaveAppFilters();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BView::MessageReceived(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AppGroupView::AddInfo(NotificationView* view)
|
||||
{
|
||||
BString id = view->MessageID();
|
||||
if (id.Length() > 0) {
|
||||
int32 children = fInfo.size();
|
||||
bool found = false;
|
||||
|
||||
for (int32 i = 0; i < children; i++) {
|
||||
if (fInfo[i]->HasMessageID(id.String())) {
|
||||
fInfo[i]->RemoveSelf();
|
||||
delete fInfo[i];
|
||||
|
||||
fInfo[i] = view;
|
||||
found = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
fInfo.push_back(view);
|
||||
} else
|
||||
fInfo.push_back(view);
|
||||
|
||||
if (fParent->IsHidden())
|
||||
fParent->Show();
|
||||
if (IsHidden())
|
||||
Show();
|
||||
if (view->IsHidden())
|
||||
view->Show();
|
||||
|
||||
AddChild(view);
|
||||
|
||||
ResizeViews();
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AppGroupView::ResizeViews()
|
||||
{
|
||||
font_height fh;
|
||||
be_bold_font->GetHeight(&fh);
|
||||
|
||||
float offset = fh.ascent + fh.leading + fh.descent;
|
||||
int32 children = fInfo.size();
|
||||
|
||||
if (!fCollapsed) {
|
||||
offset += kEdgePadding + kPenSize;
|
||||
|
||||
for (int32 i = 0; i < children; i++) {
|
||||
fInfo[i]->ResizeToPreferred();
|
||||
fInfo[i]->MoveTo(kEdgePadding + kPenSize, offset);
|
||||
|
||||
offset += fInfo[i]->Bounds().Height();
|
||||
if (fInfo[i]->IsHidden())
|
||||
fInfo[i]->Show();
|
||||
fInfo[i]->SetPosition(false, false);
|
||||
};
|
||||
} else {
|
||||
for (int32 i = 0; i < children; i++)
|
||||
if (!fInfo[i]->IsHidden())
|
||||
fInfo[i]->Hide();
|
||||
}
|
||||
|
||||
if (children == 1)
|
||||
fInfo[0]->SetPosition(true, true);
|
||||
else if (children > 1) {
|
||||
fInfo[0]->SetPosition(true, false);
|
||||
fInfo[children - 1]->SetPosition(false, true);
|
||||
}
|
||||
|
||||
ResizeTo(fParent->ViewWidth(), offset);
|
||||
float labelOffset = fh.ascent + fh.leading;
|
||||
|
||||
BRect borderRect = Bounds().InsetByCopy(kEdgePadding, kEdgePadding);
|
||||
borderRect.top = labelOffset;
|
||||
|
||||
fCollapseRect = borderRect;
|
||||
fCollapseRect.right = fCollapseRect.left + kExpandSize;
|
||||
fCollapseRect.bottom = fCollapseRect.top + kExpandSize;
|
||||
fCollapseRect.OffsetTo(kEdgePadding * 2, kEdgePadding * 1.5);
|
||||
|
||||
fCloseRect = borderRect;
|
||||
fCloseRect.right -= kEdgePadding * 4;
|
||||
fCloseRect.left = fCloseRect.right - kCloseSize;
|
||||
fCloseRect.bottom = fCloseRect.top + kCloseSize;
|
||||
fCloseRect.OffsetTo(fCloseRect.left, kEdgePadding * 1.5);
|
||||
|
||||
fParent->ResizeAll();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
AppGroupView::HasChildren()
|
||||
{
|
||||
return !fInfo.empty();
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright 2005-2008, Mikael Eiman.
|
||||
* Copyright 2005-2008, Michael Davidson.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Mikael Eiman <mikael@eiman.tv>
|
||||
* Michael Davidson <slaad@bong.com.au>
|
||||
*/
|
||||
|
||||
#ifndef APPGROUPVIEW_H
|
||||
#define APPGROUPVIEW_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <String.h>
|
||||
#include <View.h>
|
||||
|
||||
class NotificationWindow;
|
||||
class NotificationView;
|
||||
|
||||
typedef std::vector<NotificationView *> infoview_t;
|
||||
|
||||
class AppGroupView : public BView {
|
||||
public:
|
||||
AppGroupView(NotificationWindow *win, const char *label);
|
||||
~AppGroupView(void);
|
||||
|
||||
// Hooks
|
||||
void AttachedToWindow(void);
|
||||
void Draw(BRect bounds);
|
||||
void MouseDown(BPoint point);
|
||||
void GetPreferredSize(float *width, float *height);
|
||||
void MessageReceived(BMessage *msg);
|
||||
|
||||
// Public
|
||||
void AddInfo(NotificationView *view);
|
||||
void ResizeViews(void);
|
||||
bool HasChildren(void);
|
||||
|
||||
private:
|
||||
BString fLabel;
|
||||
NotificationWindow *fParent;
|
||||
infoview_t fInfo;
|
||||
bool fCollapsed;
|
||||
BRect fCloseRect;
|
||||
BRect fCollapseRect;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2008-2009, Pier Luigi Fiorini. All Rights Reserved.
|
||||
* Copyright 2004-2008, Michael Davidson. All Rights Reserved.
|
||||
* Copyright 2004-2007, Mikael Eiman. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Michael Davidson, slaad@bong.com.au
|
||||
* Mikael Eiman, mikael@eiman.tv
|
||||
* Pier Luigi Fiorini, pierluigi.fiorini@gmail.com
|
||||
*/
|
||||
|
||||
#include "BorderView.h"
|
||||
|
||||
const float kBorderWidth = 2.0f;
|
||||
const int32 kTitleSize = 14;
|
||||
|
||||
|
||||
BorderView::BorderView(BRect rect, const char* text)
|
||||
:
|
||||
BView(rect, "NotificationBorderView", B_FOLLOW_ALL,
|
||||
B_WILL_DRAW | B_FRAME_EVENTS),
|
||||
fTitle(text)
|
||||
{
|
||||
SetViewColor(B_TRANSPARENT_COLOR);
|
||||
}
|
||||
|
||||
|
||||
BorderView::~BorderView()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BorderView::FrameResized(float, float)
|
||||
{
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BorderView::Draw(BRect rect)
|
||||
{
|
||||
rgb_color col_bg = ui_color(B_PANEL_BACKGROUND_COLOR);
|
||||
rgb_color col_text = tint_color(col_bg, B_LIGHTEN_MAX_TINT);
|
||||
rgb_color col_text_shadow = tint_color(col_bg, B_DARKEN_MAX_TINT);
|
||||
|
||||
// Background
|
||||
SetDrawingMode(B_OP_COPY);
|
||||
SetHighColor(col_bg);
|
||||
FillRect(rect);
|
||||
|
||||
// Text
|
||||
SetLowColor(col_bg);
|
||||
SetDrawingMode(B_OP_ALPHA);
|
||||
SetFont(be_bold_font);
|
||||
SetFontSize(kTitleSize);
|
||||
|
||||
BFont font;
|
||||
GetFont(&font);
|
||||
|
||||
font_height fh;
|
||||
font.GetHeight(&fh);
|
||||
|
||||
// float line_height = fh.ascent + fh.descent + fh.leading;
|
||||
|
||||
float text_pos = fh.ascent;
|
||||
|
||||
SetHighColor(col_text);
|
||||
DrawString(fTitle.String(), BPoint(kBorderWidth, text_pos));
|
||||
|
||||
SetHighColor(col_text_shadow);
|
||||
DrawString(fTitle.String(), BPoint(kBorderWidth + 1, text_pos + 1));
|
||||
|
||||
// Content border
|
||||
SetHighColor(tint_color(col_bg, B_DARKEN_2_TINT));
|
||||
|
||||
BRect content = Bounds();
|
||||
content.InsetBy(kBorderWidth, kBorderWidth);
|
||||
content.top += text_pos + fh.descent + 2;
|
||||
|
||||
BRect content_line(content);
|
||||
content_line.InsetBy(-1, -1);
|
||||
|
||||
StrokeRect(content_line);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BorderView::GetPreferredSize(float* w, float* h)
|
||||
{
|
||||
SetFont(be_bold_font);
|
||||
SetFontSize(kTitleSize);
|
||||
|
||||
BFont font;
|
||||
GetFont(&font);
|
||||
|
||||
font_height fh;
|
||||
font.GetHeight(&fh);
|
||||
|
||||
float line_height = fh.ascent + fh.descent;
|
||||
|
||||
*w = 2 * kBorderWidth + StringWidth(fTitle.String());
|
||||
*h = 2 * kBorderWidth + line_height + 3;
|
||||
*w = *h = 0;
|
||||
}
|
||||
|
||||
|
||||
float
|
||||
BorderView::BorderSize()
|
||||
{
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2008-2009, Pier Luigi Fiorini. All Rights Reserved.
|
||||
* Copyright 2004-2008, Michael Davidson. All Rights Reserved.
|
||||
* Copyright 2004-2007, Mikael Eiman. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _BORDER_VIEW_H
|
||||
#define _BORDER_VIEW_H
|
||||
|
||||
#include <View.h>
|
||||
#include <String.h>
|
||||
|
||||
class BorderView : public BView {
|
||||
public:
|
||||
BorderView(BRect, const char*);
|
||||
virtual ~BorderView();
|
||||
|
||||
virtual void Draw(BRect updateRect);
|
||||
|
||||
virtual void GetPreferredSize(float*, float*);
|
||||
|
||||
virtual void FrameResized(float, float);
|
||||
|
||||
float BorderSize();
|
||||
|
||||
private:
|
||||
BString fTitle;
|
||||
};
|
||||
|
||||
#endif // _BORDER_VIEW_H
|
|
@ -0,0 +1,17 @@
|
|||
SubDir HAIKU_TOP src servers notification ;
|
||||
|
||||
UsePrivateHeaders notification ;
|
||||
UseLibraryHeaders icon ;
|
||||
|
||||
Server notification_server :
|
||||
AppGroupView.cpp
|
||||
BorderView.cpp
|
||||
NotificationServer.cpp
|
||||
NotificationView.cpp
|
||||
NotificationWindow.cpp
|
||||
: be $(TARGET_LIBSTDC++) libicon.a libnotification.a
|
||||
: notification_server.rdef
|
||||
;
|
||||
|
||||
Depends notification_server : libicon.a ;
|
||||
Depends notification_server : libnotification.a ;
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Pier Luigi Fiorini, pierluigi.fiorini@gmail.com
|
||||
*/
|
||||
|
||||
#include <Beep.h>
|
||||
#include <Notifications.h>
|
||||
|
||||
#include "NotificationWindow.h"
|
||||
#include "NotificationServer.h"
|
||||
|
||||
const char* kSoundNames[] = {
|
||||
"Information notification",
|
||||
"Important notification",
|
||||
"Error notification",
|
||||
"Progress notification",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
NotificationServer::NotificationServer()
|
||||
: BApplication(kNotificationServerSignature)
|
||||
{
|
||||
fWindow = new NotificationWindow();
|
||||
}
|
||||
|
||||
|
||||
NotificationServer::~NotificationServer()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NotificationServer::MessageReceived(BMessage* message)
|
||||
{
|
||||
switch (message->what) {
|
||||
case kNotificationMessage:
|
||||
{
|
||||
// Skip this message if we don't have the window
|
||||
if (!fWindow)
|
||||
return;
|
||||
|
||||
int32 type = 0;
|
||||
|
||||
// Emit a sound for this event
|
||||
if (message->FindInt32("type", &type) == B_OK) {
|
||||
if (type < (int32)(sizeof(kSoundNames) / sizeof(const char*)))
|
||||
system_beep(kSoundNames[type]);
|
||||
}
|
||||
|
||||
// Let the notification window handle this message
|
||||
BMessenger(fWindow).SendMessage(message);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BApplication::MessageReceived(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
NotificationServer::QuitRequested()
|
||||
{
|
||||
if (fWindow && fWindow->Lock()) {
|
||||
fWindow->Quit();
|
||||
fWindow = NULL;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
NotificationServer::GetSupportedSuites(BMessage* msg)
|
||||
{
|
||||
msg->AddString("suites", "suite/x-vnd.Haiku-notification_server");
|
||||
|
||||
BPropertyInfo info(main_prop_list);
|
||||
msg->AddFlat("messages", &info);
|
||||
|
||||
return BApplication::GetSupportedSuites(msg);
|
||||
}
|
||||
|
||||
|
||||
BHandler*
|
||||
NotificationServer::ResolveSpecifier(BMessage* msg, int32 index,
|
||||
BMessage* spec, int32 from, const char* prop)
|
||||
{
|
||||
BPropertyInfo info(main_prop_list);
|
||||
|
||||
if (strcmp(prop, "message") == 0) {
|
||||
BMessenger messenger(fWindow);
|
||||
messenger.SendMessage(msg, fWindow);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return BApplication::ResolveSpecifier(msg, index, spec, from, prop);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
int32 i = 0;
|
||||
|
||||
// Add system sounds
|
||||
while (kSoundNames[i] != NULL)
|
||||
add_system_beep_event(kSoundNames[i++], 0);
|
||||
|
||||
// Start!
|
||||
NotificationServer* server = new NotificationServer();
|
||||
server->Run();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _NOTIFICATION_SERVER_H
|
||||
#define _NOTIFICATION_SERVER_H
|
||||
|
||||
#include <Application.h>
|
||||
|
||||
class NotificationWindow;
|
||||
|
||||
class NotificationServer : public BApplication {
|
||||
public:
|
||||
NotificationServer();
|
||||
virtual ~NotificationServer();
|
||||
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
virtual bool QuitRequested();
|
||||
|
||||
virtual status_t GetSupportedSuites(BMessage* msg);
|
||||
virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index, BMessage* spec,
|
||||
int32 form, const char* prop);
|
||||
|
||||
private:
|
||||
NotificationWindow* fWindow;
|
||||
};
|
||||
|
||||
#endif // _NOTIFICATION_SERVER_H
|
|
@ -0,0 +1,720 @@
|
|||
/*
|
||||
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2008-2009, Pier Luigi Fiorini. All Rights Reserved.
|
||||
* Copyright 2004-2008, Michael Davidson. All Rights Reserved.
|
||||
* Copyright 2004-2007, Mikael Eiman. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Michael Davidson, slaad@bong.com.au
|
||||
* Mikael Eiman, mikael@eiman.tv
|
||||
* Pier Luigi Fiorini, pierluigi.fiorini@gmail.com
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <Font.h>
|
||||
#include <IconUtils.h>
|
||||
#include <Messenger.h>
|
||||
#include <Picture.h>
|
||||
#include <PropertyInfo.h>
|
||||
#include <Region.h>
|
||||
#include <Resources.h>
|
||||
#include <Roster.h>
|
||||
#include <StringView.h>
|
||||
#include <TranslationUtils.h>
|
||||
|
||||
#include "NotificationView.h"
|
||||
#include "NotificationWindow.h"
|
||||
|
||||
const char* kSmallIconAttribute = "BEOS:M:STD_ICON";
|
||||
const char* kLargeIconAttribute = "BEOS:L:STD_ICON";
|
||||
const char* kIconAttribute = "BEOS:ICON";
|
||||
|
||||
property_info message_prop_list[] = {
|
||||
{ "type", {B_GET_PROPERTY, B_SET_PROPERTY, 0},
|
||||
{B_DIRECT_SPECIFIER, 0}, "get the notification type"},
|
||||
{ "app", {B_GET_PROPERTY, B_SET_PROPERTY, 0},
|
||||
{B_DIRECT_SPECIFIER, 0}, "get notification's app"},
|
||||
{ "title", {B_GET_PROPERTY, B_SET_PROPERTY, 0},
|
||||
{B_DIRECT_SPECIFIER, 0}, "get notification's title"},
|
||||
{ "content", {B_GET_PROPERTY, B_SET_PROPERTY, 0},
|
||||
{B_DIRECT_SPECIFIER, 0}, "get notification's contents"},
|
||||
{ "icon", {B_GET_PROPERTY, 0},
|
||||
{B_DIRECT_SPECIFIER, 0}, "get icon as an archived bitmap"},
|
||||
{ "progress", {B_GET_PROPERTY, B_SET_PROPERTY, 0},
|
||||
{B_DIRECT_SPECIFIER, 0}, "get the progress (between 0.0 and 1.0)"},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
|
||||
NotificationView::NotificationView(NotificationWindow* win,
|
||||
notification_type type, const char* app, const char* title, const char* text,
|
||||
BMessage* details)
|
||||
:
|
||||
BView(BRect(0, 0, win->ViewWidth(), 1), "NotificationView",
|
||||
B_FOLLOW_LEFT_RIGHT, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE
|
||||
| B_FRAME_EVENTS),
|
||||
fParent(win),
|
||||
fType(type),
|
||||
fRunner(NULL),
|
||||
fProgress(0.0f),
|
||||
fMessageID(""),
|
||||
fDetails(details),
|
||||
fBitmap(NULL),
|
||||
fIsFirst(false),
|
||||
fIsLast(false)
|
||||
{
|
||||
BMessage iconMsg;
|
||||
if (fDetails->FindMessage("icon", &iconMsg) == B_OK)
|
||||
fBitmap = new BBitmap(&iconMsg);
|
||||
|
||||
if (!fBitmap)
|
||||
_LoadIcon();
|
||||
|
||||
const char* messageID = NULL;
|
||||
if (fDetails->FindString("messageID", &messageID) == B_OK)
|
||||
fMessageID = messageID;
|
||||
|
||||
if (fDetails->FindFloat("progress", &fProgress) != B_OK)
|
||||
fProgress = 0.0f;
|
||||
|
||||
// Progress is between 0 and 1
|
||||
if (fProgress < 0.0f)
|
||||
fProgress = 0.0f;
|
||||
if (fProgress > 1.0f)
|
||||
fProgress = 1.0f;
|
||||
|
||||
SetText(app, title, text);
|
||||
ResizeToPreferred();
|
||||
|
||||
switch (type) {
|
||||
case B_IMPORTANT_NOTIFICATION:
|
||||
SetViewColor(255, 255, 255);
|
||||
SetLowColor(255, 255, 255);
|
||||
break;
|
||||
case B_ERROR_NOTIFICATION:
|
||||
SetViewColor(ui_color(B_FAILURE_COLOR));
|
||||
SetLowColor(ui_color(B_FAILURE_COLOR));
|
||||
break;
|
||||
default:
|
||||
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
NotificationView::~NotificationView()
|
||||
{
|
||||
delete fRunner;
|
||||
delete fDetails;
|
||||
delete fBitmap;
|
||||
|
||||
LineInfoList::iterator lIt;
|
||||
for (lIt = fLines.begin(); lIt != fLines.end(); lIt++)
|
||||
delete (*lIt);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NotificationView::AttachedToWindow()
|
||||
{
|
||||
BMessage msg(kRemoveView);
|
||||
msg.AddPointer("view", this);
|
||||
int32 timeout = -1;
|
||||
|
||||
if (fDetails->FindInt32("timeout", &timeout) != B_OK)
|
||||
timeout = fParent->Timeout();
|
||||
bigtime_t delay = timeout * 1000 * 1000;
|
||||
|
||||
if (delay > 0)
|
||||
fRunner = new BMessageRunner(BMessenger(Parent()), &msg, delay, 1);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NotificationView::MessageReceived(BMessage* msg)
|
||||
{
|
||||
switch (msg->what) {
|
||||
case B_GET_PROPERTY:
|
||||
{
|
||||
BMessage specifier;
|
||||
const char* property;
|
||||
BMessage reply(B_REPLY);
|
||||
bool msgOkay = true;
|
||||
|
||||
if (msg->FindMessage("specifiers", 0, &specifier) != B_OK)
|
||||
msgOkay = false;
|
||||
if (specifier.FindString("property", &property) != B_OK)
|
||||
msgOkay = false;
|
||||
|
||||
if (msgOkay) {
|
||||
if (strcmp(property, "type") == 0)
|
||||
reply.AddInt32("result", fType);
|
||||
|
||||
if (strcmp(property, "app") == 0)
|
||||
reply.AddString("result", fApp);
|
||||
|
||||
if (strcmp(property, "title") == 0)
|
||||
reply.AddString("result", fTitle);
|
||||
|
||||
if (strcmp(property, "content") == 0)
|
||||
reply.AddString("result", fText);
|
||||
|
||||
if (strcmp(property, "progress") == 0)
|
||||
reply.AddFloat("result", fProgress);
|
||||
|
||||
if ((strcmp(property, "icon") == 0) && fBitmap) {
|
||||
BMessage archive;
|
||||
if (fBitmap->Archive(&archive) == B_OK)
|
||||
reply.AddMessage("result", &archive);
|
||||
}
|
||||
|
||||
reply.AddInt32("error", B_OK);
|
||||
} else {
|
||||
reply.what = B_MESSAGE_NOT_UNDERSTOOD;
|
||||
reply.AddInt32("error", B_ERROR);
|
||||
}
|
||||
|
||||
msg->SendReply(&reply);
|
||||
break;
|
||||
}
|
||||
case B_SET_PROPERTY:
|
||||
{
|
||||
BMessage specifier;
|
||||
const char* property;
|
||||
BMessage reply(B_REPLY);
|
||||
bool msgOkay = true;
|
||||
|
||||
if (msg->FindMessage("specifiers", 0, &specifier) != B_OK)
|
||||
msgOkay = false;
|
||||
if (specifier.FindString("property", &property) != B_OK)
|
||||
msgOkay = false;
|
||||
|
||||
if (msgOkay) {
|
||||
if (strcmp(property, "app") == 0)
|
||||
msg->FindString("data", &fApp);
|
||||
|
||||
if (strcmp(property, "title") == 0)
|
||||
msg->FindString("data", &fTitle);
|
||||
|
||||
if (strcmp(property, "content") == 0)
|
||||
msg->FindString("data", &fText);
|
||||
|
||||
if (strcmp(property, "icon") == 0) {
|
||||
BMessage archive;
|
||||
if (msg->FindMessage("data", &archive) == B_OK) {
|
||||
delete fBitmap;
|
||||
fBitmap = new BBitmap(&archive);
|
||||
}
|
||||
}
|
||||
|
||||
SetText(Application(), Title(), Text());
|
||||
Invalidate();
|
||||
|
||||
reply.AddInt32("error", B_OK);
|
||||
} else {
|
||||
reply.what = B_MESSAGE_NOT_UNDERSTOOD;
|
||||
reply.AddInt32("error", B_ERROR);
|
||||
}
|
||||
|
||||
msg->SendReply(&reply);
|
||||
break;
|
||||
}
|
||||
case kRemoveView:
|
||||
{
|
||||
BMessage remove(kRemoveView);
|
||||
remove.AddPointer("view", this);
|
||||
BMessenger msgr(Window());
|
||||
msgr.SendMessage( &remove );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BView::MessageReceived(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NotificationView::GetPreferredSize(float* w, float* h)
|
||||
{
|
||||
// Parent width, minus the edge padding, minus the pensize
|
||||
*w = fParent->ViewWidth() - (kEdgePadding * 2) - (kPenSize * 2);
|
||||
*h = fHeight;
|
||||
|
||||
if (fType == B_PROGRESS_NOTIFICATION) {
|
||||
font_height fh;
|
||||
be_plain_font->GetHeight(&fh);
|
||||
float fontHeight = fh.ascent + fh.descent + fh.leading;
|
||||
*h += (kSmallPadding * 2) + (kEdgePadding * 1) + fontHeight;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NotificationView::Draw(BRect updateRect)
|
||||
{
|
||||
BRect progRect;
|
||||
|
||||
// Draw progress background
|
||||
if (fType == B_PROGRESS_NOTIFICATION) {
|
||||
PushState();
|
||||
|
||||
font_height fh;
|
||||
be_plain_font->GetHeight(&fh);
|
||||
float fontHeight = fh.ascent + fh.descent + fh.leading;
|
||||
|
||||
progRect = Bounds();
|
||||
progRect.InsetBy(kEdgePadding, kEdgePadding);
|
||||
progRect.top = progRect.bottom - (kSmallPadding * 2) - fontHeight;
|
||||
StrokeRect(progRect);
|
||||
|
||||
BRect barRect = progRect;
|
||||
barRect.InsetBy(1.0, 1.0);
|
||||
barRect.right *= fProgress;
|
||||
SetHighColor(ui_color(B_CONTROL_HIGHLIGHT_COLOR));
|
||||
FillRect(barRect);
|
||||
|
||||
SetHighColor(ui_color(B_PANEL_TEXT_COLOR));
|
||||
|
||||
BString label = "";
|
||||
label << (int)(fProgress * 100) << " %";
|
||||
|
||||
float labelWidth = be_plain_font->StringWidth(label.String());
|
||||
float labelX = progRect.left + (progRect.IntegerWidth() / 2) - (labelWidth / 2);
|
||||
|
||||
SetLowColor(B_TRANSPARENT_COLOR);
|
||||
SetDrawingMode(B_OP_ALPHA);
|
||||
DrawString(label.String(), label.Length(),
|
||||
BPoint(labelX, progRect.top + fh.ascent + fh.leading + kSmallPadding));
|
||||
|
||||
PopState();
|
||||
}
|
||||
|
||||
SetDrawingMode(B_OP_ALPHA);
|
||||
SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
|
||||
|
||||
// Icon size
|
||||
float iconSize = (float)fParent->IconSize();
|
||||
|
||||
// Rectangle for icon and overlay icon
|
||||
BRect iconRect(0, 0, 0, 0);
|
||||
|
||||
// Draw icon
|
||||
if (fBitmap) {
|
||||
LineInfo* appLine = fLines.back();
|
||||
font_height fh;
|
||||
appLine->font.GetHeight(&fh);
|
||||
|
||||
float title_bottom = appLine->location.y + fh.descent;
|
||||
|
||||
float ix = kEdgePadding;
|
||||
float iy = 0;
|
||||
if (fParent->Layout() == TitleAboveIcon)
|
||||
iy = title_bottom + kEdgePadding + (Bounds().Height() - title_bottom
|
||||
- kEdgePadding * 2 - iconSize) / 2;
|
||||
else
|
||||
iy = (Bounds().Height() - iconSize) / 2.0;
|
||||
|
||||
if (fType == B_PROGRESS_NOTIFICATION)
|
||||
// Move icon up by half progress bar height if it's present
|
||||
iy -= (progRect.Height() + kEdgePadding) / 2.0;
|
||||
|
||||
iconRect.left = ix;
|
||||
iconRect.top = iy;
|
||||
iconRect.right = ix + iconSize;
|
||||
iconRect.bottom = iy + iconSize;
|
||||
|
||||
DrawBitmapAsync(fBitmap, fBitmap->Bounds(),
|
||||
iconRect, B_FILTER_BITMAP_BILINEAR);
|
||||
}
|
||||
|
||||
// Draw content
|
||||
LineInfoList::iterator lIt;
|
||||
for (lIt = fLines.begin(); lIt != fLines.end(); lIt++) {
|
||||
LineInfo *l = (*lIt);
|
||||
|
||||
SetFont(&l->font);
|
||||
DrawString(l->text.String(), l->text.Length(), l->location);
|
||||
}
|
||||
|
||||
rgb_color detailCol = ui_color(B_CONTROL_BORDER_COLOR);
|
||||
detailCol = tint_color(detailCol, B_LIGHTEN_2_TINT);
|
||||
|
||||
// Draw the close widget
|
||||
BRect closeRect = Bounds();
|
||||
closeRect.InsetBy(kEdgePadding, kEdgePadding);
|
||||
closeRect.left = closeRect.right - kCloseSize;
|
||||
closeRect.bottom = closeRect.top + kCloseSize;
|
||||
|
||||
PushState();
|
||||
SetHighColor(detailCol);
|
||||
StrokeRoundRect(closeRect, kSmallPadding, kSmallPadding);
|
||||
BRect closeCross = closeRect.InsetByCopy(kSmallPadding, kSmallPadding);
|
||||
StrokeLine(closeCross.LeftTop(), closeCross.RightBottom());
|
||||
StrokeLine(closeCross.LeftBottom(), closeCross.RightTop());
|
||||
PopState();
|
||||
|
||||
Sync();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NotificationView::MouseDown(BPoint point)
|
||||
{
|
||||
int32 buttons;
|
||||
Window()->CurrentMessage()->FindInt32("buttons", &buttons);
|
||||
|
||||
switch (buttons) {
|
||||
case B_PRIMARY_MOUSE_BUTTON:
|
||||
{
|
||||
BRect closeRect = Bounds().InsetByCopy(2,2);
|
||||
closeRect.left = closeRect.right - kCloseSize;
|
||||
closeRect.bottom = closeRect.top + kCloseSize;
|
||||
|
||||
if (!closeRect.Contains(point)) {
|
||||
entry_ref launchRef;
|
||||
BString launchString;
|
||||
BMessage argMsg(B_ARGV_RECEIVED);
|
||||
BMessage refMsg(B_REFS_RECEIVED);
|
||||
entry_ref appRef;
|
||||
bool useArgv = false;
|
||||
BList messages;
|
||||
entry_ref ref;
|
||||
|
||||
if (fDetails->FindString("onClickApp", &launchString) == B_OK)
|
||||
if (be_roster->FindApp(launchString.String(), &appRef) == B_OK)
|
||||
useArgv = true;
|
||||
if (fDetails->FindRef("onClickFile", &launchRef) == B_OK) {
|
||||
if (be_roster->FindApp(&launchRef, &appRef) == B_OK)
|
||||
useArgv = true;
|
||||
}
|
||||
|
||||
if (fDetails->FindRef("onClickRef", &ref) == B_OK) {
|
||||
for (int32 i = 0; fDetails->FindRef("onClickRef", i, &ref) == B_OK; i++)
|
||||
refMsg.AddRef("refs", &ref);
|
||||
|
||||
messages.AddItem((void*)&refMsg);
|
||||
}
|
||||
|
||||
if (useArgv) {
|
||||
type_code type;
|
||||
int32 argc = 0;
|
||||
BString arg;
|
||||
|
||||
BPath p(&appRef);
|
||||
argMsg.AddString("argv", p.Path());
|
||||
|
||||
fDetails->GetInfo("onClickArgv", &type, &argc);
|
||||
argMsg.AddInt32("argc", argc + 1);
|
||||
|
||||
for (int32 i = 0; fDetails->FindString("onClickArgv", i, &arg) == B_OK; i++)
|
||||
argMsg.AddString("argv", arg);
|
||||
|
||||
messages.AddItem((void*)&argMsg);
|
||||
}
|
||||
|
||||
BMessage tmp;
|
||||
for (int32 i = 0; fDetails->FindMessage("onClickMsg", i, &tmp) == B_OK; i++)
|
||||
messages.AddItem((void*)&tmp);
|
||||
|
||||
if (fDetails->FindString("onClickApp", &launchString) == B_OK)
|
||||
be_roster->Launch(launchString.String(), &messages);
|
||||
else
|
||||
be_roster->Launch(&launchRef, &messages);
|
||||
}
|
||||
|
||||
// Remove the info view after a click
|
||||
BMessage remove_msg(kRemoveView);
|
||||
remove_msg.AddPointer("view", this);
|
||||
|
||||
BMessenger msgr(Parent());
|
||||
msgr.SendMessage(&remove_msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NotificationView::FrameResized( float w, float /*h*/)
|
||||
{
|
||||
SetText(Application(), Title(), Text());
|
||||
}
|
||||
|
||||
|
||||
BHandler*
|
||||
NotificationView::ResolveSpecifier(BMessage* msg, int32 index, BMessage* spec, int32 form, const char* prop)
|
||||
{
|
||||
BPropertyInfo prop_info(message_prop_list);
|
||||
if (prop_info.FindMatch(msg, index, spec, form, prop) >= 0) {
|
||||
msg->PopSpecifier();
|
||||
return this;
|
||||
}
|
||||
|
||||
return BView::ResolveSpecifier(msg, index, spec, form, prop);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
NotificationView::GetSupportedSuites(BMessage* msg)
|
||||
{
|
||||
msg->AddString("suites", "suite/x-vnd.Haiku-notification_server");
|
||||
BPropertyInfo prop_info(message_prop_list);
|
||||
msg->AddFlat("messages", &prop_info);
|
||||
return BView::GetSupportedSuites(msg);
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
NotificationView::Application() const
|
||||
{
|
||||
return fApp.Length() > 0 ? fApp.String() : NULL;
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
NotificationView::Title() const
|
||||
{
|
||||
return fTitle.Length() > 0 ? fTitle.String() : NULL;
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
NotificationView::Text() const
|
||||
{
|
||||
return fText.Length() > 0 ? fText.String() : NULL;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NotificationView::SetText(const char* app, const char* title, const char* text,
|
||||
float newMaxWidth)
|
||||
{
|
||||
if (newMaxWidth < 0)
|
||||
newMaxWidth = Bounds().Width() - (kEdgePadding * 2);
|
||||
|
||||
// Delete old lines
|
||||
LineInfoList::iterator lIt;
|
||||
for (lIt = fLines.begin(); lIt != fLines.end(); lIt++)
|
||||
delete (*lIt);
|
||||
fLines.clear();
|
||||
|
||||
fApp = app;
|
||||
fTitle = title;
|
||||
fText = text;
|
||||
|
||||
float iconRight = kEdgePadding + kEdgePadding;
|
||||
if (fBitmap != NULL)
|
||||
iconRight += fParent->IconSize();
|
||||
|
||||
font_height fh;
|
||||
be_bold_font->GetHeight(&fh);
|
||||
float fontHeight = ceilf(fh.leading) + ceilf(fh.descent)
|
||||
+ ceilf(fh.ascent);
|
||||
float y = fontHeight;
|
||||
|
||||
// Title
|
||||
LineInfo* titleLine = new LineInfo;
|
||||
titleLine->text = fTitle;
|
||||
titleLine->font = *be_bold_font;
|
||||
|
||||
if (fParent->Layout() == AllTextRightOfIcon)
|
||||
titleLine->location = BPoint(iconRight, y);
|
||||
else
|
||||
titleLine->location = BPoint(kEdgePadding, y);
|
||||
|
||||
fLines.push_front(titleLine);
|
||||
y += fontHeight;
|
||||
|
||||
// Rest of text is rendered with be_plain_font.
|
||||
be_plain_font->GetHeight(&fh);
|
||||
fontHeight = ceilf(fh.leading) + ceilf(fh.descent)
|
||||
+ ceilf(fh.ascent);
|
||||
|
||||
// Split text into chunks between certain characters and compose the lines.
|
||||
const char kSeparatorCharacters[] = " \n-\\/";
|
||||
BString textBuffer = fText;
|
||||
textBuffer.ReplaceAll("\t", " ");
|
||||
const char* chunkStart = textBuffer.String();
|
||||
float maxWidth = newMaxWidth - kEdgePadding - iconRight;
|
||||
LineInfo* line = NULL;
|
||||
ssize_t length = textBuffer.Length();
|
||||
while (chunkStart - textBuffer.String() < length) {
|
||||
size_t chunkLength = strcspn(chunkStart, kSeparatorCharacters) + 1;
|
||||
|
||||
// Start a new line if either we didn't start one before,
|
||||
// the current offset
|
||||
BString tempText(line != NULL ? line->text : "");
|
||||
tempText.Append(chunkStart, chunkLength);
|
||||
|
||||
if (line == NULL || chunkStart[0] == '\n'
|
||||
|| StringWidth(tempText) > maxWidth) {
|
||||
line = new LineInfo;
|
||||
line->font = *be_plain_font;
|
||||
line->location = BPoint(iconRight + kEdgePadding, y);
|
||||
|
||||
fLines.push_front(line);
|
||||
y += fontHeight;
|
||||
|
||||
// Skip the eventual new-line character at the beginning of this
|
||||
// chunk.
|
||||
if (chunkStart[0] == '\n') {
|
||||
chunkStart++;
|
||||
chunkLength--;
|
||||
}
|
||||
// Skip more new-line characters and move the line further down.
|
||||
while (chunkStart[0] == '\n') {
|
||||
chunkStart++;
|
||||
chunkLength--;
|
||||
line->location.y += fontHeight;
|
||||
y += fontHeight;
|
||||
}
|
||||
// Strip space at beginning of a new line.
|
||||
while (chunkStart[0] == ' ') {
|
||||
chunkLength--;
|
||||
chunkStart++;
|
||||
}
|
||||
}
|
||||
|
||||
if (chunkStart[0] == '\0')
|
||||
break;
|
||||
|
||||
// Append the chunk to the current line, which was either a new
|
||||
// line or the one from the previous iteration.
|
||||
line->text.Append(chunkStart, chunkLength);
|
||||
|
||||
chunkStart += chunkLength;
|
||||
}
|
||||
|
||||
fHeight = y + (kEdgePadding * 2);
|
||||
|
||||
// Make sure icon fits
|
||||
if (fBitmap != NULL) {
|
||||
float minHeight = 0;
|
||||
if (fParent->Layout() == TitleAboveIcon) {
|
||||
LineInfo* appLine = fLines.back();
|
||||
font_height fh;
|
||||
appLine->font.GetHeight(&fh);
|
||||
minHeight = appLine->location.y + fh.descent;
|
||||
}
|
||||
|
||||
minHeight += fBitmap->Bounds().Height() + 2 * kEdgePadding;
|
||||
if (fHeight < minHeight)
|
||||
fHeight = minHeight;
|
||||
}
|
||||
|
||||
BMessenger(Parent()).SendMessage(kResizeToFit);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
NotificationView::HasMessageID(const char* id)
|
||||
{
|
||||
return fMessageID == id;
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
NotificationView::MessageID()
|
||||
{
|
||||
return fMessageID.String();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NotificationView::SetPosition(bool first, bool last)
|
||||
{
|
||||
fIsFirst = first;
|
||||
fIsLast = last;
|
||||
}
|
||||
|
||||
|
||||
BBitmap*
|
||||
NotificationView::_ReadNodeIcon(const char* fileName, icon_size size)
|
||||
{
|
||||
BEntry entry(fileName, true);
|
||||
|
||||
entry_ref ref;
|
||||
entry.GetRef(&ref);
|
||||
|
||||
BNode node(BPath(&ref).Path());
|
||||
|
||||
BBitmap* ret = new BBitmap(BRect(0, 0, (float)size - 1, (float)size - 1), B_RGBA32);
|
||||
if (BIconUtils::GetIcon(&node, kIconAttribute, kSmallIconAttribute,
|
||||
kLargeIconAttribute, size, ret) != B_OK) {
|
||||
delete ret;
|
||||
ret = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NotificationView::_LoadIcon()
|
||||
{
|
||||
// First try to get the icon from the caller application
|
||||
app_info info;
|
||||
BMessenger msgr = fDetails->ReturnAddress();
|
||||
|
||||
if (msgr.IsValid())
|
||||
be_roster->GetRunningAppInfo(msgr.Team(), &info);
|
||||
else if (fType == B_PROGRESS_NOTIFICATION)
|
||||
be_roster->GetAppInfo("application/x-vnd.Haiku-notification_server",
|
||||
&info);
|
||||
|
||||
BPath path;
|
||||
path.SetTo(&info.ref);
|
||||
|
||||
fBitmap = _ReadNodeIcon(path.Path(), fParent->IconSize());
|
||||
if (fBitmap)
|
||||
return;
|
||||
|
||||
// If that failed get icons from app_server
|
||||
if (find_directory(B_BEOS_SERVERS_DIRECTORY, &path) != B_OK)
|
||||
return;
|
||||
|
||||
path.Append("app_server");
|
||||
|
||||
BFile file(path.Path(), B_READ_ONLY);
|
||||
if (file.InitCheck() != B_OK)
|
||||
return;
|
||||
|
||||
BResources res(&file);
|
||||
if (res.InitCheck() != B_OK)
|
||||
return;
|
||||
|
||||
// Which one should we choose?
|
||||
const char* iconName = "";
|
||||
switch (fType) {
|
||||
case B_INFORMATION_NOTIFICATION:
|
||||
iconName = "info";
|
||||
break;
|
||||
case B_ERROR_NOTIFICATION:
|
||||
iconName = "stop";
|
||||
break;
|
||||
case B_IMPORTANT_NOTIFICATION:
|
||||
iconName = "warn";
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
// Allocate the bitmap
|
||||
fBitmap = new BBitmap(BRect(0, 0, (float)B_LARGE_ICON - 1,
|
||||
(float)B_LARGE_ICON - 1), B_RGBA32);
|
||||
if (!fBitmap || fBitmap->InitCheck() != B_OK) {
|
||||
fBitmap = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
// Load raw icon data
|
||||
size_t size = 0;
|
||||
const uint8* data = (const uint8*)res.LoadResource(B_VECTOR_ICON_TYPE,
|
||||
iconName, &size);
|
||||
if ((data == NULL
|
||||
|| BIconUtils::GetVectorIcon(data, size, fBitmap) != B_OK))
|
||||
fBitmap = NULL;
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2008-2009, Pier Luigi Fiorini. All Rights Reserved.
|
||||
* Copyright 2004-2008, Michael Davidson. All Rights Reserved.
|
||||
* Copyright 2004-2007, Mikael Eiman. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _NOTIFICATION_VIEW_H
|
||||
#define _NOTIFICATION_VIEW_H
|
||||
|
||||
#include <list>
|
||||
|
||||
#include <Bitmap.h>
|
||||
#include <Entry.h>
|
||||
#include <Message.h>
|
||||
#include <MessageRunner.h>
|
||||
#include <MimeType.h>
|
||||
#include <Notification.h>
|
||||
#include <Path.h>
|
||||
#include <Roster.h>
|
||||
#include <String.h>
|
||||
#include <TextView.h>
|
||||
#include <View.h>
|
||||
|
||||
class NotificationWindow;
|
||||
|
||||
const uint32 kRemoveView = 'ReVi';
|
||||
|
||||
class NotificationView : public BView {
|
||||
public:
|
||||
NotificationView(NotificationWindow* win,
|
||||
notification_type type,
|
||||
const char* app, const char* title,
|
||||
const char* text, BMessage* details);
|
||||
virtual ~NotificationView();
|
||||
|
||||
virtual void AttachedToWindow();
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
virtual void GetPreferredSize(float* width, float* height);
|
||||
virtual void Draw(BRect updateRect);
|
||||
virtual void MouseDown(BPoint point);
|
||||
virtual void FrameResized(float width, float height);
|
||||
|
||||
virtual BHandler* ResolveSpecifier(BMessage* msg, int32 index,
|
||||
BMessage* specifier, int32 form,
|
||||
const char* property);
|
||||
virtual status_t GetSupportedSuites(BMessage* msg);
|
||||
|
||||
const char* Application() const;
|
||||
const char* Title() const;
|
||||
const char* Text() const;
|
||||
|
||||
void SetText(const char* app, const char* title,
|
||||
const char* text, float newMaxWidth = -1);
|
||||
bool HasMessageID(const char* id);
|
||||
const char* MessageID();
|
||||
void SetPosition(bool first, bool last);
|
||||
|
||||
private:
|
||||
BBitmap* _ReadNodeIcon(const char* fileName,
|
||||
icon_size size);
|
||||
void _LoadIcon();
|
||||
|
||||
private:
|
||||
struct LineInfo {
|
||||
BFont font;
|
||||
BString text;
|
||||
BPoint location;
|
||||
};
|
||||
|
||||
typedef std::list<LineInfo*> LineInfoList;
|
||||
|
||||
|
||||
NotificationWindow* fParent;
|
||||
|
||||
notification_type fType;
|
||||
BMessageRunner* fRunner;
|
||||
float fProgress;
|
||||
BString fMessageID;
|
||||
|
||||
BMessage* fDetails;
|
||||
BBitmap* fBitmap;
|
||||
|
||||
LineInfoList fLines;
|
||||
|
||||
BString fApp;
|
||||
BString fTitle;
|
||||
BString fText;
|
||||
|
||||
float fHeight;
|
||||
|
||||
bool fIsFirst;
|
||||
bool fIsLast;
|
||||
};
|
||||
|
||||
#endif // _NOTIFICATION_VIEW_H
|
|
@ -0,0 +1,598 @@
|
|||
/*
|
||||
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2008-2009, Pier Luigi Fiorini. All Rights Reserved.
|
||||
* Copyright 2004-2008, Michael Davidson. All Rights Reserved.
|
||||
* Copyright 2004-2007, Mikael Eiman. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Michael Davidson, slaad@bong.com.au
|
||||
* Mikael Eiman, mikael@eiman.tv
|
||||
* Pier Luigi Fiorini, pierluigi.fiorini@gmail.com
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <Alert.h>
|
||||
#include <Application.h>
|
||||
#include <Debug.h>
|
||||
#include <File.h>
|
||||
#include <NodeMonitor.h>
|
||||
#include <PropertyInfo.h>
|
||||
|
||||
#include "AppGroupView.h"
|
||||
#include "AppUsage.h"
|
||||
#include "BorderView.h"
|
||||
#include "NotificationWindow.h"
|
||||
|
||||
property_info main_prop_list[] = {
|
||||
{ "message", {B_GET_PROPERTY, 0}, {B_INDEX_SPECIFIER, 0}, "get a message"},
|
||||
{ "message", {B_COUNT_PROPERTIES, 0}, {B_DIRECT_SPECIFIER, 0}, "count messages"},
|
||||
{ "message", {B_CREATE_PROPERTY, 0}, {B_DIRECT_SPECIFIER, 0}, "create a message"},
|
||||
{ "message", {B_SET_PROPERTY, 0}, {B_INDEX_SPECIFIER, 0 }, "modify a message" },
|
||||
0
|
||||
};
|
||||
|
||||
const float kCloseSize = 8;
|
||||
const float kExpandSize = 8;
|
||||
const float kPenSize = 1;
|
||||
const float kEdgePadding = 5;
|
||||
const float kSmallPadding = 2;
|
||||
|
||||
|
||||
NotificationWindow::NotificationWindow()
|
||||
:
|
||||
BWindow(BRect(10, 10, 30, 30), "Notification", B_BORDERED_WINDOW,
|
||||
B_AVOID_FRONT | B_AVOID_FOCUS | B_NOT_CLOSABLE | B_NOT_ZOOMABLE
|
||||
| B_NOT_MINIMIZABLE | B_NOT_RESIZABLE, B_ALL_WORKSPACES)
|
||||
{
|
||||
fBorder = new BorderView(Bounds(), "Notification");
|
||||
|
||||
AddChild(fBorder);
|
||||
|
||||
Show();
|
||||
Hide();
|
||||
|
||||
LoadSettings(true);
|
||||
LoadAppFilters(true);
|
||||
}
|
||||
|
||||
|
||||
NotificationWindow::~NotificationWindow()
|
||||
{
|
||||
appfilter_t::iterator aIt;
|
||||
for (aIt = fAppFilters.begin(); aIt != fAppFilters.end(); aIt++)
|
||||
delete aIt->second;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
NotificationWindow::QuitRequested()
|
||||
{
|
||||
appview_t::iterator aIt;
|
||||
for (aIt = fAppViews.begin(); aIt != fAppViews.end(); aIt++) {
|
||||
aIt->second->RemoveSelf();
|
||||
delete aIt->second;
|
||||
}
|
||||
|
||||
BMessenger(be_app).SendMessage(B_QUIT_REQUESTED);
|
||||
return BWindow::QuitRequested();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NotificationWindow::WorkspaceActivated(int32 /*workspace*/, bool active)
|
||||
{
|
||||
// Ensure window is in the correct position
|
||||
if (active)
|
||||
ResizeAll();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NotificationWindow::MessageReceived(BMessage* message)
|
||||
{
|
||||
switch (message->what) {
|
||||
case B_NODE_MONITOR:
|
||||
{
|
||||
LoadSettings();
|
||||
LoadAppFilters();
|
||||
break;
|
||||
}
|
||||
case kResizeToFit:
|
||||
ResizeAll();
|
||||
break;
|
||||
case B_COUNT_PROPERTIES:
|
||||
{
|
||||
BMessage reply(B_REPLY);
|
||||
BMessage specifier;
|
||||
const char* property = NULL;
|
||||
bool messageOkay = true;
|
||||
|
||||
if (message->FindMessage("specifiers", 0, &specifier) != B_OK)
|
||||
messageOkay = false;
|
||||
if (specifier.FindString("property", &property) != B_OK)
|
||||
messageOkay = false;
|
||||
if (strcmp(property, "message") != 0)
|
||||
messageOkay = false;
|
||||
|
||||
if (messageOkay)
|
||||
reply.AddInt32("result", fViews.size());
|
||||
else {
|
||||
reply.what = B_MESSAGE_NOT_UNDERSTOOD;
|
||||
reply.AddInt32("error", B_ERROR);
|
||||
}
|
||||
|
||||
message->SendReply(&reply);
|
||||
break;
|
||||
}
|
||||
case B_CREATE_PROPERTY:
|
||||
case kNotificationMessage:
|
||||
{
|
||||
int32 type;
|
||||
const char* content = NULL;
|
||||
const char* title = NULL;
|
||||
const char* app = NULL;
|
||||
BMessage reply(B_REPLY);
|
||||
bool messageOkay = true;
|
||||
|
||||
if (message->FindInt32("type", &type) != B_OK)
|
||||
type = B_INFORMATION_NOTIFICATION;
|
||||
if (message->FindString("content", &content) != B_OK)
|
||||
messageOkay = false;
|
||||
if (message->FindString("title", &title) != B_OK)
|
||||
messageOkay = false;
|
||||
if (message->FindString("app", &app) != B_OK && message->FindString("appTitle", &app) != B_OK)
|
||||
messageOkay = false;
|
||||
|
||||
if (messageOkay) {
|
||||
NotificationView* view = new NotificationView(this, (notification_type)type, app,
|
||||
title, content, new BMessage(*message));
|
||||
|
||||
appfilter_t::iterator fIt = fAppFilters.find(app);
|
||||
bool allow = false;
|
||||
if (fIt == fAppFilters.end()) {
|
||||
app_info info;
|
||||
BMessenger messenger = message->ReturnAddress();
|
||||
if (messenger.IsValid())
|
||||
be_roster->GetRunningAppInfo(messenger.Team(), &info);
|
||||
else
|
||||
be_roster->GetAppInfo("application/x-vnd.Be-SHEL", &info);
|
||||
|
||||
AppUsage* appUsage = new AppUsage(info.ref, app, true);
|
||||
fAppFilters[app] = appUsage;
|
||||
|
||||
appUsage->Allowed(title, (notification_type)type);
|
||||
|
||||
allow = true;
|
||||
} else
|
||||
allow = fIt->second->Allowed(title, (notification_type)type);
|
||||
|
||||
if (allow) {
|
||||
appview_t::iterator aIt = fAppViews.find(app);
|
||||
AppGroupView *group = NULL;
|
||||
if (aIt == fAppViews.end()) {
|
||||
group = new AppGroupView(this, app);
|
||||
fAppViews[app] = group;
|
||||
fBorder->AddChild(group);
|
||||
} else {
|
||||
group = aIt->second;
|
||||
};
|
||||
group->AddInfo(view);
|
||||
|
||||
ResizeAll();
|
||||
|
||||
reply.AddInt32("error", B_OK);
|
||||
} else
|
||||
reply.AddInt32("Error", B_ERROR);
|
||||
} else {
|
||||
reply.what = B_MESSAGE_NOT_UNDERSTOOD;
|
||||
reply.AddInt32("error", B_ERROR);
|
||||
}
|
||||
|
||||
message->SendReply(&reply);
|
||||
break;
|
||||
}
|
||||
case kRemoveView:
|
||||
{
|
||||
void* _ptr;
|
||||
message->FindPointer("view", &_ptr);
|
||||
|
||||
NotificationView* info
|
||||
= reinterpret_cast<NotificationView*>(_ptr);
|
||||
|
||||
fBorder->RemoveChild(info);
|
||||
|
||||
std::vector<NotificationView*>::iterator i
|
||||
= find(fViews.begin(), fViews.end(), info);
|
||||
if (i != fViews.end())
|
||||
fViews.erase(i);
|
||||
|
||||
delete info;
|
||||
|
||||
ResizeAll();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BWindow::MessageReceived(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BHandler*
|
||||
NotificationWindow::ResolveSpecifier(BMessage *msg, int32 index,
|
||||
BMessage *spec, int32 form, const char *prop)
|
||||
{
|
||||
BPropertyInfo prop_info(main_prop_list);
|
||||
BHandler* handler = NULL;
|
||||
|
||||
if (strcmp(prop,"message") == 0) {
|
||||
switch (msg->what) {
|
||||
case B_CREATE_PROPERTY:
|
||||
{
|
||||
msg->PopSpecifier();
|
||||
handler = this;
|
||||
break;
|
||||
}
|
||||
case B_SET_PROPERTY:
|
||||
case B_GET_PROPERTY:
|
||||
{
|
||||
int32 i;
|
||||
|
||||
if (spec->FindInt32("index", &i) != B_OK)
|
||||
i = -1;
|
||||
|
||||
if (i >= 0 && i < (int32)fViews.size()) {
|
||||
msg->PopSpecifier();
|
||||
handler = fViews[i];
|
||||
} else
|
||||
handler = NULL;
|
||||
break;
|
||||
}
|
||||
case B_COUNT_PROPERTIES:
|
||||
msg->PopSpecifier();
|
||||
handler = this;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!handler)
|
||||
handler = BWindow::ResolveSpecifier(msg, index, spec, form, prop);
|
||||
|
||||
return handler;
|
||||
}
|
||||
|
||||
|
||||
icon_size
|
||||
NotificationWindow::IconSize()
|
||||
{
|
||||
return fIconSize;
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
NotificationWindow::Timeout()
|
||||
{
|
||||
return fTimeout;
|
||||
}
|
||||
|
||||
|
||||
|
||||
infoview_layout
|
||||
NotificationWindow::Layout()
|
||||
{
|
||||
return fLayout;
|
||||
}
|
||||
|
||||
|
||||
float
|
||||
NotificationWindow::ViewWidth()
|
||||
{
|
||||
return fWidth;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NotificationWindow::ResizeAll()
|
||||
{
|
||||
if (fAppViews.empty()) {
|
||||
if (!IsHidden())
|
||||
Hide();
|
||||
return;
|
||||
}
|
||||
|
||||
appview_t::iterator aIt;
|
||||
bool shouldHide = true;
|
||||
|
||||
for (aIt = fAppViews.begin(); aIt != fAppViews.end(); aIt++) {
|
||||
AppGroupView *app = aIt->second;
|
||||
if (app->HasChildren()) {
|
||||
shouldHide = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldHide) {
|
||||
if (!IsHidden())
|
||||
Hide();
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsHidden())
|
||||
Show();
|
||||
|
||||
float width = 0;
|
||||
float height = 0;
|
||||
|
||||
for (aIt = fAppViews.begin(); aIt != fAppViews.end(); aIt++) {
|
||||
AppGroupView* view = aIt->second;
|
||||
float w = -1;
|
||||
float h = -1;
|
||||
|
||||
if (!view->HasChildren()) {
|
||||
if (!view->IsHidden())
|
||||
view->Hide();
|
||||
} else {
|
||||
view->GetPreferredSize(&w, &h);
|
||||
width = max_c(width, h);
|
||||
|
||||
view->ResizeToPreferred();
|
||||
view->MoveTo(0, height);
|
||||
|
||||
height += h;
|
||||
|
||||
if (view->IsHidden())
|
||||
view->Show();
|
||||
}
|
||||
}
|
||||
|
||||
ResizeTo(ViewWidth(), height);
|
||||
PopupAnimation(Bounds().Width(), Bounds().Height());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NotificationWindow::PopupAnimation(float width, float height)
|
||||
{
|
||||
float x = 0, y = 0, sx, sy;
|
||||
float pad = 0;
|
||||
BDeskbar deskbar;
|
||||
BRect frame = deskbar.Frame();
|
||||
|
||||
switch (deskbar.Location()) {
|
||||
case B_DESKBAR_TOP:
|
||||
// Put it just under, top right corner
|
||||
sx = frame.right;
|
||||
sy = frame.bottom+pad;
|
||||
y = sy;
|
||||
x = sx-width-pad;
|
||||
break;
|
||||
case B_DESKBAR_BOTTOM:
|
||||
// Put it just above, lower left corner
|
||||
sx = frame.right;
|
||||
sy = frame.top-height-pad;
|
||||
y = sy;
|
||||
x = sx - width-pad;
|
||||
break;
|
||||
case B_DESKBAR_LEFT_TOP:
|
||||
// Put it just to the right of the deskbar
|
||||
sx = frame.right+pad;
|
||||
sy = frame.top-height;
|
||||
x = sx;
|
||||
y = frame.top+pad;
|
||||
break;
|
||||
case B_DESKBAR_RIGHT_TOP:
|
||||
// Put it just to the left of the deskbar
|
||||
sx = frame.left-width-pad;
|
||||
sy = frame.top-height;
|
||||
x = sx;
|
||||
y = frame.top+pad;
|
||||
break;
|
||||
case B_DESKBAR_LEFT_BOTTOM:
|
||||
// Put it to the right of the deskbar.
|
||||
sx = frame.right+pad;
|
||||
sy = frame.bottom;
|
||||
x = sx;
|
||||
y = sy-height-pad;
|
||||
break;
|
||||
case B_DESKBAR_RIGHT_BOTTOM:
|
||||
// Put it to the left of the deskbar.
|
||||
sx = frame.left-width-pad;
|
||||
sy = frame.bottom;
|
||||
y = sy-height-pad;
|
||||
x = sx;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
MoveTo(x, y);
|
||||
|
||||
if (IsHidden() && fViews.size() != 0)
|
||||
Show();
|
||||
//Activate();// it hides floaters from apps :-(
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NotificationWindow::LoadSettings(bool startMonitor)
|
||||
{
|
||||
_LoadGeneralSettings(startMonitor);
|
||||
_LoadDisplaySettings(startMonitor);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NotificationWindow::LoadAppFilters(bool startMonitor)
|
||||
{
|
||||
BPath path;
|
||||
|
||||
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
|
||||
return;
|
||||
|
||||
path.Append(kSettingsDirectory);
|
||||
|
||||
if (create_directory(path.Path(), 0755) != B_OK)
|
||||
return;
|
||||
|
||||
path.Append(kFiltersSettings);
|
||||
|
||||
BFile file(path.Path(), B_READ_ONLY);
|
||||
BMessage settings;
|
||||
if (settings.Unflatten(&file) != B_OK)
|
||||
return;
|
||||
|
||||
type_code type;
|
||||
int32 count = 0;
|
||||
|
||||
if (settings.GetInfo("app_usage", &type, &count) != B_OK)
|
||||
return;
|
||||
|
||||
for (int32 i = 0; i < count; i++) {
|
||||
AppUsage* app = new AppUsage();
|
||||
settings.FindFlat("app_usage", i, app);
|
||||
fAppFilters[app->Name()] = app;
|
||||
}
|
||||
|
||||
if (startMonitor) {
|
||||
node_ref nref;
|
||||
BEntry entry(path.Path());
|
||||
entry.GetNodeRef(&nref);
|
||||
|
||||
if (watch_node(&nref, B_WATCH_ALL, BMessenger(this)) != B_OK) {
|
||||
BAlert* alert = new BAlert("", "Couldn't start filter "
|
||||
" monitor. Live filter changes disabled.", "Darn.");
|
||||
alert->Go();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NotificationWindow::SaveAppFilters()
|
||||
{
|
||||
BPath path;
|
||||
|
||||
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
|
||||
return;
|
||||
|
||||
path.Append(kSettingsDirectory);
|
||||
path.Append(kFiltersSettings);
|
||||
|
||||
BMessage settings;
|
||||
BFile file(path.Path(), B_WRITE_ONLY);
|
||||
|
||||
appfilter_t::iterator fIt;
|
||||
for (fIt = fAppFilters.begin(); fIt != fAppFilters.end(); fIt++)
|
||||
settings.AddFlat("app_usage", fIt->second);
|
||||
|
||||
settings.Flatten(&file);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NotificationWindow::_LoadGeneralSettings(bool startMonitor)
|
||||
{
|
||||
BPath path;
|
||||
BMessage settings;
|
||||
|
||||
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
|
||||
return;
|
||||
|
||||
path.Append(kSettingsDirectory);
|
||||
if (create_directory(path.Path(), 0755) == B_OK) {
|
||||
path.Append(kGeneralSettings);
|
||||
|
||||
BFile file(path.Path(), B_READ_ONLY);
|
||||
settings.Unflatten(&file);
|
||||
}
|
||||
|
||||
if (settings.FindInt32(kTimeoutName, &fTimeout) != B_OK)
|
||||
fTimeout = kDefaultTimeout;
|
||||
|
||||
// Notify the view about the change
|
||||
views_t::iterator it;
|
||||
for (it = fViews.begin(); it != fViews.end(); ++it) {
|
||||
NotificationView* view = (*it);
|
||||
view->SetText(view->Application(), view->Title(), view->Text());
|
||||
view->Invalidate();
|
||||
}
|
||||
|
||||
if (startMonitor) {
|
||||
node_ref nref;
|
||||
BEntry entry(path.Path());
|
||||
entry.GetNodeRef(&nref);
|
||||
|
||||
if (watch_node(&nref, B_WATCH_ALL, BMessenger(this)) != B_OK) {
|
||||
BAlert* alert = new BAlert("", "Couldn't start general settings "
|
||||
" monitor.\nLive filter changes disabled.", "OK");
|
||||
alert->Go();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NotificationWindow::_LoadDisplaySettings(bool startMonitor)
|
||||
{
|
||||
BPath path;
|
||||
BMessage settings;
|
||||
|
||||
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
|
||||
return;
|
||||
|
||||
path.Append(kSettingsDirectory);
|
||||
if (create_directory(path.Path(), 0755) == B_OK) {
|
||||
path.Append(kDisplaySettings);
|
||||
|
||||
BFile file(path.Path(), B_READ_ONLY);
|
||||
settings.Unflatten(&file);
|
||||
}
|
||||
|
||||
int32 setting;
|
||||
|
||||
if (settings.FindFloat(kWidthName, &fWidth) != B_OK)
|
||||
fWidth = kDefaultWidth;
|
||||
|
||||
if (settings.FindInt32(kIconSizeName, &setting) != B_OK)
|
||||
fIconSize = kDefaultIconSize;
|
||||
else
|
||||
fIconSize = (icon_size)setting;
|
||||
|
||||
if (settings.FindInt32(kLayoutName, &setting) != B_OK)
|
||||
fLayout = kDefaultLayout;
|
||||
else {
|
||||
switch (setting) {
|
||||
case 0:
|
||||
fLayout = TitleAboveIcon;
|
||||
break;
|
||||
case 1:
|
||||
fLayout = AllTextRightOfIcon;
|
||||
break;
|
||||
default:
|
||||
fLayout = kDefaultLayout;
|
||||
}
|
||||
}
|
||||
|
||||
// Notify the view about the change
|
||||
views_t::iterator it;
|
||||
for (it = fViews.begin(); it != fViews.end(); ++it) {
|
||||
NotificationView* view = (*it);
|
||||
view->SetText(view->Application(), view->Title(), view->Text());
|
||||
view->Invalidate();
|
||||
}
|
||||
|
||||
if (startMonitor) {
|
||||
node_ref nref;
|
||||
BEntry entry(path.Path());
|
||||
entry.GetNodeRef(&nref);
|
||||
|
||||
if (watch_node(&nref, B_WATCH_ALL, BMessenger(this)) != B_OK) {
|
||||
BAlert* alert = new BAlert("", "Couldn't start display settings "
|
||||
" monitor.\nLive filter changes disabled.", "OK");
|
||||
alert->Go();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Copyright 2010, Haiku, Inc. All Rights Reserved.
|
||||
* Copyright 2008-2009, Pier Luigi Fiorini. All Rights Reserved.
|
||||
* Copyright 2004-2008, Michael Davidson. All Rights Reserved.
|
||||
* Copyright 2004-2007, Mikael Eiman. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef _NOTIFICATION_WINDOW_H
|
||||
#define _NOTIFICATION_WINDOW_H
|
||||
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include <Directory.h>
|
||||
#include <Deskbar.h>
|
||||
#include <Entry.h>
|
||||
#include <FindDirectory.h>
|
||||
#include <Message.h>
|
||||
#include <Notifications.h>
|
||||
#include <PropertyInfo.h>
|
||||
#include <String.h>
|
||||
#include <Window.h>
|
||||
|
||||
#include "NotificationView.h"
|
||||
|
||||
class AppGroupView;
|
||||
class AppUsage;
|
||||
class BorderView;
|
||||
class SettingsFile;
|
||||
|
||||
typedef std::map<BString, AppGroupView*> appview_t;
|
||||
typedef std::map<BString, AppUsage*> appfilter_t;
|
||||
typedef std::vector<NotificationView*> views_t;
|
||||
|
||||
extern const float kEdgePadding;
|
||||
extern const float kSmallPadding;
|
||||
extern const float kCloseSize;
|
||||
extern const float kExpandSize;
|
||||
extern const float kPenSize;
|
||||
|
||||
const uint32 kResizeToFit = 'IWrf';
|
||||
|
||||
class NotificationWindow : public BWindow {
|
||||
public:
|
||||
NotificationWindow();
|
||||
virtual ~NotificationWindow();
|
||||
|
||||
virtual bool QuitRequested();
|
||||
virtual void MessageReceived(BMessage*);
|
||||
virtual void WorkspaceActivated(int32, bool);
|
||||
virtual BHandler* ResolveSpecifier(BMessage*, int32, BMessage*,
|
||||
int32, const char*);
|
||||
|
||||
icon_size IconSize();
|
||||
int32 Timeout();
|
||||
infoview_layout Layout();
|
||||
float ViewWidth();
|
||||
|
||||
void ResizeAll();
|
||||
|
||||
private:
|
||||
friend class AppGroupView;
|
||||
|
||||
void PopupAnimation(float, float);
|
||||
void LoadSettings(bool startMonitor = false);
|
||||
void LoadAppFilters(bool startMonitor = false);
|
||||
void SaveAppFilters();
|
||||
void _LoadGeneralSettings(bool startMonitor);
|
||||
void _LoadDisplaySettings(bool startMonitor);
|
||||
|
||||
views_t fViews;
|
||||
BorderView* fBorder;
|
||||
|
||||
appview_t fAppViews;
|
||||
|
||||
BString fStatusText;
|
||||
BString fMessageText;
|
||||
|
||||
float fWidth;
|
||||
icon_size fIconSize;
|
||||
int32 fTimeout;
|
||||
infoview_layout fLayout;
|
||||
|
||||
appfilter_t fAppFilters;
|
||||
};
|
||||
|
||||
extern property_info main_prop_list[];
|
||||
|
||||
#endif // _NOTIFICATION_WINDOW_H
|
|
@ -0,0 +1,33 @@
|
|||
|
||||
resource app_signature "application/x-vnd.Haiku-notification_server";
|
||||
|
||||
resource app_flags B_EXCLUSIVE_LAUNCH | B_BACKGROUND_APP;
|
||||
|
||||
resource app_version {
|
||||
major = 1,
|
||||
middle = 0,
|
||||
minor = 0,
|
||||
|
||||
variety = B_APPV_ALPHA,
|
||||
internal = 0,
|
||||
|
||||
short_info = "notification_server",
|
||||
long_info = "notification_server ©2010 Haiku Inc."
|
||||
};
|
||||
|
||||
resource vector_icon {
|
||||
$"6E636966060401780501020106023A06C63967B3B838E138A51E4B2EAA46CD17"
|
||||
$"C3677F93FFFFFFFF02030603BF80A63DDD21BA0661BBABD34BDD9CC05D0900FF"
|
||||
$"DA8F3EFFAA008290600202030603BBE0A53C15CEB9A968B967964C2B2D459EFF"
|
||||
$"00FFDA8F29FFAA0054906002020106053CFCDB3CFBB1BB18EC3B1A2148FE2D4A"
|
||||
$"C91D89FFFFFFA8BAC6D1C3677F93E2BAC6D1FFFFFFFF040406FE034460C6E460"
|
||||
$"C4C6605460575C565E585A5E345E3460335D2E61305D2E4400054E244E24C5DB"
|
||||
$"B453C756B4915123C756B491562655255727C95329C95329592B592E592D592E"
|
||||
$"0616FFABAAAAAA0A4E244E24C5DBB453C756B4915123C756B491562655255727"
|
||||
$"C95329C95329592B592E592D592E4957475A425C3C5B365832552F532C50284C"
|
||||
$"264924462242213F203B2136233425330A1A4957475A425C3C5B365832552F53"
|
||||
$"2C50284C264924462242213F203B2136233425332C333135353738393F3F4344"
|
||||
$"4547484D4950070A000100000A01010130222201178822040A01010230222201"
|
||||
$"178400040A02010130222201178422040A0301022022220A0401032022220A05"
|
||||
$"0103123FBBD40000000000003FA51943DCFC44C1340117840004"
|
||||
};
|
Loading…
Reference in New Issue