Notification_Server: Added ability to choose position of notifications

The feature gives user ability to choose the position of notifications
out of Follow Deskbar, Lower Right, Lower Left, Upper Right and Upper
Left. Fixes #9749 - Notification_Server: add the ability to choose the
position of notifications (easy).

Signed-off-by: Adrien Destugues <pulkomandy@pulkomandy.tk>
This commit is contained in:
Hrishi Hiraskar 2017-12-11 16:24:02 +05:30 committed by Adrien Destugues
parent e229bf70b8
commit 226f6c8bf1
6 changed files with 197 additions and 35 deletions

View File

@ -6,10 +6,13 @@
#define _NOTIFICATIONS_H
#include <Mime.h>
#include <View.h>
#include <String.h>
#define kNotificationServerSignature "application/x-vnd.Haiku-notification_server"
#define B_FOLLOW_DESKBAR B_FOLLOW_NONE
// Messages
const uint32 kNotificationMessage = 'nssm';
@ -21,6 +24,7 @@ extern const char* kAutoStartName;
extern const char* kTimeoutName;
extern const char* kWidthName;
extern const char* kIconSizeName;
extern const char* kNotificationPositionName;
// General default settings
const bool kDefaultAutoStart = true;
@ -32,5 +36,6 @@ const float kMinimumWidth = 300.0f;
const float kMaximumWidth = 1000.0f;
const int32 kWidthStep = 50;
const icon_size kDefaultIconSize = B_LARGE_ICON;
const uint32 kDefaultNotificationPosition = B_FOLLOW_DESKBAR;
#endif // _NOTIFICATIONS_H

View File

@ -43,10 +43,27 @@
const uint32 kToggleNotifications = '_TSR';
const uint32 kWidthChanged = '_WIC';
const uint32 kTimeoutChanged = '_TIC';
const uint32 kPositionChanged = '_NPC';
const uint32 kServerChangeTriggered = '_SCT';
const BString kSampleMessageID("NotificationsSample");
static int32
notification_position_to_index(uint32 notification_position) {
if (notification_position == B_FOLLOW_NONE)
return 0;
else if (notification_position == (B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM))
return 1;
else if (notification_position == (B_FOLLOW_LEFT | B_FOLLOW_BOTTOM))
return 2;
else if (notification_position == (B_FOLLOW_RIGHT | B_FOLLOW_TOP))
return 3;
else if (notification_position == (B_FOLLOW_LEFT | B_FOLLOW_TOP))
return 4;
return 0;
}
GeneralView::GeneralView(SettingsHost* host)
:
SettingsPane("general", host)
@ -87,10 +104,37 @@ GeneralView::GeneralView(SettingsHost* host)
B_TRANSLATE_COMMENT(minLabel.String(), "Slider low text"),
B_TRANSLATE_COMMENT(maxLabel.String(), "Slider high text"));
// Notification Position
fPositionMenu = new BPopUpMenu(B_TRANSLATE("Follow Deskbar"));
const char* positionLabels[] = {
B_TRANSLATE_MARK("Follow Deskbar"),
B_TRANSLATE_MARK("Lower right"),
B_TRANSLATE_MARK("Lower left"),
B_TRANSLATE_MARK("Upper right"),
B_TRANSLATE_MARK("Upper left")
};
const uint32 positions[] = {
B_FOLLOW_DESKBAR, // Follow Deskbar
B_FOLLOW_BOTTOM | B_FOLLOW_RIGHT, // Lower right
B_FOLLOW_BOTTOM | B_FOLLOW_LEFT, // Lower left
B_FOLLOW_TOP | B_FOLLOW_RIGHT, // Upper right
B_FOLLOW_TOP | B_FOLLOW_LEFT // Upper left
};
for (int i=0; i < 5; i++) {
BMessage* message = new BMessage(kPositionChanged);
message->AddInt32(kNotificationPositionName, positions[i]);
fPositionMenu->AddItem(new BMenuItem(B_TRANSLATE_NOCOLLECT(
positionLabels[i]), message));
}
BMenuField* positionField = new BMenuField(B_TRANSLATE("Position:"),
fPositionMenu);
box->AddChild(BLayoutBuilder::Group<>(B_VERTICAL)
.SetInsets(B_USE_DEFAULT_SPACING)
.Add(fWidthSlider)
.Add(fDurationSlider)
.Add(positionField)
.AddGlue()
.View());
@ -108,6 +152,7 @@ GeneralView::AttachedToWindow()
fNotificationBox->SetTarget(this);
fWidthSlider->SetTarget(this);
fDurationSlider->SetTarget(this);
fPositionMenu->SetTargetForItems(this);
}
@ -134,6 +179,15 @@ GeneralView::MessageReceived(BMessage* msg)
SettingsPane::SettingsChanged(true);
break;
}
case kPositionChanged:
{
int32 position;
if (msg->FindInt32(kNotificationPositionName, &position) == B_OK) {
fNewPosition = position;
SettingsPane::SettingsChanged(true);
}
break;
}
default:
BView::MessageReceived(msg);
break;
@ -163,6 +217,12 @@ GeneralView::Load(BMessage& settings)
else
fOriginalIconSize = (icon_size)setting;
int32 position;
if (settings.FindInt32(kNotificationPositionName, &position) != B_OK)
fOriginalPosition = kDefaultNotificationPosition;
else
fOriginalPosition = position;
_EnableControls();
return Revert();
@ -184,6 +244,8 @@ GeneralView::Save(BMessage& settings)
icon_size iconSize = B_LARGE_ICON;
settings.AddInt32(kIconSizeName, (int32)iconSize);
settings.AddInt32(kNotificationPositionName, (int32)fNewPosition);
return B_OK;
}
@ -196,6 +258,12 @@ GeneralView::Revert()
fWidthSlider->SetValue(fOriginalWidth / 50);
_SetWidthLabel(fOriginalWidth);
fNewPosition = fOriginalPosition;
BMenuItem* item = fPositionMenu->ItemAt(
notification_position_to_index(fNewPosition));
if (item != NULL)
item->SetMarked(true);
return B_OK;
}
@ -212,6 +280,9 @@ GeneralView::RevertPossible()
if (fOriginalWidth != width)
return true;
if (fOriginalPosition != fNewPosition)
return true;
return false;
}
@ -225,6 +296,12 @@ GeneralView::Defaults()
fWidthSlider->SetValue(kDefaultWidth / 50);
_SetWidthLabel(kDefaultWidth);
fNewPosition = kDefaultNotificationPosition;
BMenuItem* item = fPositionMenu->ItemAt(
notification_position_to_index(fNewPosition));
if (item != NULL)
item->SetMarked(true);
return B_OK;
}
@ -239,6 +316,9 @@ GeneralView::DefaultsPossible()
int32 width = fWidthSlider->Value() * 50;
if (kDefaultWidth != width)
return true;
if (kDefaultNotificationPosition != fNewPosition)
return true;
return false;
}
@ -257,6 +337,10 @@ GeneralView::_EnableControls()
bool enabled = fNotificationBox->Value() == B_CONTROL_ON;
fWidthSlider->SetEnabled(enabled);
fDurationSlider->SetEnabled(enabled);
BMenuItem* item = fPositionMenu->ItemAt(
notification_position_to_index(fOriginalPosition));
if (item != NULL)
item->SetMarked(true);
}

View File

@ -12,6 +12,7 @@
#include <Menu.h>
#include <MenuField.h>
#include <Mime.h>
#include <PopUpMenu.h>
#include <RadioButton.h>
#include <Slider.h>
#include <StringView.h>
@ -40,10 +41,14 @@ private:
BCheckBox* fNotificationBox;
BSlider* fDurationSlider;
BSlider* fWidthSlider;
BPopUpMenu* fPositionMenu;
int32 fOriginalTimeout;
float fOriginalWidth;
icon_size fOriginalIconSize;
uint32 fOriginalPosition;
uint32 fNewPosition;
void _EnableControls();
void _SetWidthLabel(int32 value);

View File

@ -26,7 +26,9 @@
#include <NodeMonitor.h>
#include <Notifications.h>
#include <Path.h>
#include <Point.h>
#include <PropertyInfo.h>
#include <Screen.h>
#include "AppGroupView.h"
#include "AppUsage.h"
@ -50,6 +52,37 @@ property_info main_prop_list[] = {
};
/**
* Checks if notification position overlaps with
* deskbar position
*/
static bool
is_overlapping(deskbar_location deskbar,
uint32 notification) {
if (deskbar == B_DESKBAR_RIGHT_TOP
&& notification == (B_FOLLOW_RIGHT | B_FOLLOW_TOP))
return true;
if (deskbar == B_DESKBAR_RIGHT_BOTTOM
&& notification == (B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM))
return true;
if (deskbar == B_DESKBAR_LEFT_TOP
&& notification == (B_FOLLOW_LEFT | B_FOLLOW_TOP))
return true;
if (deskbar == B_DESKBAR_LEFT_BOTTOM
&& notification == (B_FOLLOW_LEFT | B_FOLLOW_BOTTOM))
return true;
if (deskbar == B_DESKBAR_TOP
&& (notification == (B_FOLLOW_LEFT | B_FOLLOW_TOP)
|| notification == (B_FOLLOW_RIGHT | B_FOLLOW_TOP)))
return true;
if (deskbar == B_DESKBAR_BOTTOM
&& (notification == (B_FOLLOW_LEFT | B_FOLLOW_BOTTOM)
|| notification == (B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM)))
return true;
return false;
}
NotificationWindow::NotificationWindow()
:
BWindow(BRect(0, 0, -1, -1), B_TRANSLATE_MARK("Notification"),
@ -63,7 +96,7 @@ NotificationWindow::NotificationWindow()
fCachePath.Append("Notifications");
BDirectory cacheDir;
result = cacheDir.SetTo(fCachePath.Path());
if(result == B_ENTRY_NOT_FOUND)
if (result == B_ENTRY_NOT_FOUND)
cacheDir.CreateDirectory(fCachePath.Path(), NULL);
SetLayout(new BGroupLayout(B_VERTICAL, 0));
@ -146,8 +179,8 @@ NotificationWindow::MessageReceived(BMessage* message)
BString sourceName(notification->SourceName());
bool allow = false;
appfilter_t::iterator it =
fAppFilters.find(sourceSignature.String());
appfilter_t::iterator it = fAppFilters
.find(sourceSignature.String());
AppUsage* appUsage = NULL;
if (it == fAppFilters.end()) {
@ -275,43 +308,70 @@ NotificationWindow::SetPosition()
float x = Frame().left;
float y = Frame().top;
// If we can't guess, don't move...
// If we cant guess, don't move...
BPoint location(x, y);
BDeskbar deskbar;
BRect frame = deskbar.Frame();
switch (deskbar.Location()) {
case B_DESKBAR_TOP:
// Put it just under, top right corner
y = frame.bottom + topOffset;
x = frame.right - width + rightOffset;
break;
case B_DESKBAR_BOTTOM:
// Put it just above, lower left corner
y = frame.top - height - bottomOffset;
x = frame.right - width + rightOffset;
break;
case B_DESKBAR_RIGHT_TOP:
x = frame.left - width - rightOffset;
y = frame.top - topOffset + 1;
break;
case B_DESKBAR_LEFT_TOP:
x = frame.right + leftOffset;
y = frame.top - topOffset + 1;
break;
case B_DESKBAR_RIGHT_BOTTOM:
y = frame.bottom - height + bottomOffset;
x = frame.left - width - rightOffset;
break;
case B_DESKBAR_LEFT_BOTTOM:
y = frame.bottom - height + bottomOffset;
x = frame.right + leftOffset;
break;
default:
break;
// If notification and deskbar position are same
// then follow deskbar position
uint32 position = (is_overlapping(deskbar.Location(), fPosition))
? B_FOLLOW_DESKBAR
: fPosition;
if (position == B_FOLLOW_DESKBAR)
{
BRect frame = deskbar.Frame();
switch (deskbar.Location()) {
case B_DESKBAR_TOP:
// In case of overlapping here or for bottom
// use user's notification position
y = frame.bottom + topOffset;
x = (fPosition == B_FOLLOW_LEFT | B_FOLLOW_TOP)
? frame.left + rightOffset
: frame.right - width + rightOffset;
break;
case B_DESKBAR_BOTTOM:
y = frame.top - height - bottomOffset;
x = (fPosition == B_FOLLOW_LEFT | B_FOLLOW_BOTTOM)
? frame.left + rightOffset
: frame.right - width + rightOffset;
break;
case B_DESKBAR_RIGHT_TOP:
y = frame.top - topOffset + 1;
x = frame.left - width - rightOffset;
break;
case B_DESKBAR_LEFT_TOP:
y = frame.top - topOffset + 1;
x = frame.right + leftOffset;
break;
case B_DESKBAR_RIGHT_BOTTOM:
y = frame.bottom - height + bottomOffset;
x = frame.left - width - rightOffset;
break;
case B_DESKBAR_LEFT_BOTTOM:
y = frame.bottom - height + bottomOffset;
x = frame.right + leftOffset;
break;
default:
break;
}
location = BPoint(x, y);
} else if (position == (B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM)) {
location = BScreen().Frame().RightBottom();
location -= BPoint(width, height);
} else if (position == (B_FOLLOW_LEFT | B_FOLLOW_BOTTOM)) {
location = BScreen().Frame().LeftBottom();
location -= BPoint(0, height);
} else if (position == (B_FOLLOW_RIGHT | B_FOLLOW_TOP)) {
location = BScreen().Frame().RightTop();
location -= BPoint(width, 0);
} else if (position == (B_FOLLOW_LEFT | B_FOLLOW_TOP)) {
location = BScreen().Frame().LeftTop();
}
MoveTo(x, y);
MoveTo(location);
}
@ -402,6 +462,12 @@ NotificationWindow::_LoadDisplaySettings(BMessage& settings)
else
fIconSize = (icon_size)setting;
int32 position;
if (settings.FindInt32(kNotificationPositionName, &position) != B_OK)
fPosition = kDefaultNotificationPosition;
else
fPosition = position;
// Notify the views about the change
appview_t::iterator aIt;
for (aIt = fAppViews.begin(); aIt != fAppViews.end(); ++aIt) {

View File

@ -63,6 +63,7 @@ private:
float fWidth;
icon_size fIconSize;
int32 fTimeout;
uint32 fPosition;
bool fShouldRun;
BPath fCachePath;
};

View File

@ -17,3 +17,4 @@ const char* kTimeoutName = "timeout";
// Display settings
const char* kWidthName = "width";
const char* kIconSizeName = "icon size";
const char* kNotificationPositionName = "notification position";