From 226f6c8bf18d1d1250d91dc630de3662bdc03ec8 Mon Sep 17 00:00:00 2001 From: Hrishi Hiraskar Date: Mon, 11 Dec 2017 16:24:02 +0530 Subject: [PATCH] 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 --- headers/private/notification/Notifications.h | 5 + src/preferences/notifications/GeneralView.cpp | 84 +++++++++++ src/preferences/notifications/GeneralView.h | 5 + .../notification/NotificationWindow.cpp | 136 +++++++++++++----- src/servers/notification/NotificationWindow.h | 1 + src/servers/notification/Notifications.cpp | 1 + 6 files changed, 197 insertions(+), 35 deletions(-) diff --git a/headers/private/notification/Notifications.h b/headers/private/notification/Notifications.h index 18298a4270..2f3ac9ec4f 100644 --- a/headers/private/notification/Notifications.h +++ b/headers/private/notification/Notifications.h @@ -6,10 +6,13 @@ #define _NOTIFICATIONS_H #include +#include #include #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 diff --git a/src/preferences/notifications/GeneralView.cpp b/src/preferences/notifications/GeneralView.cpp index bbd831f138..bde36889d6 100644 --- a/src/preferences/notifications/GeneralView.cpp +++ b/src/preferences/notifications/GeneralView.cpp @@ -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); } diff --git a/src/preferences/notifications/GeneralView.h b/src/preferences/notifications/GeneralView.h index 0bd5a084b1..9106cee1b3 100644 --- a/src/preferences/notifications/GeneralView.h +++ b/src/preferences/notifications/GeneralView.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -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); diff --git a/src/servers/notification/NotificationWindow.cpp b/src/servers/notification/NotificationWindow.cpp index bad3683f98..f00a5fdb3d 100644 --- a/src/servers/notification/NotificationWindow.cpp +++ b/src/servers/notification/NotificationWindow.cpp @@ -26,7 +26,9 @@ #include #include #include +#include #include +#include #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) { diff --git a/src/servers/notification/NotificationWindow.h b/src/servers/notification/NotificationWindow.h index f4325a9ae2..8861453c60 100644 --- a/src/servers/notification/NotificationWindow.h +++ b/src/servers/notification/NotificationWindow.h @@ -63,6 +63,7 @@ private: float fWidth; icon_size fIconSize; int32 fTimeout; + uint32 fPosition; bool fShouldRun; BPath fCachePath; }; diff --git a/src/servers/notification/Notifications.cpp b/src/servers/notification/Notifications.cpp index 3dfcb1e713..d49f0c3e15 100644 --- a/src/servers/notification/Notifications.cpp +++ b/src/servers/notification/Notifications.cpp @@ -17,3 +17,4 @@ const char* kTimeoutName = "timeout"; // Display settings const char* kWidthName = "width"; const char* kIconSizeName = "icon size"; +const char* kNotificationPositionName = "notification position";