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";