Address cpplint issue "Lines should be <= 80 characters long [whitespace/line_length] [2]"
This commit is contained in:
parent
392d606848
commit
0bba5b9b41
16 changed files with 238 additions and 106 deletions
|
@ -22,7 +22,8 @@ NotificationPresenterLinux::NotificationPresenterLinux() {
|
||||||
NotificationPresenterLinux::~NotificationPresenterLinux() {
|
NotificationPresenterLinux::~NotificationPresenterLinux() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Notification* NotificationPresenterLinux::CreateNotificationObject(NotificationDelegate* delegate) {
|
Notification* NotificationPresenterLinux::CreateNotificationObject(
|
||||||
|
NotificationDelegate* delegate) {
|
||||||
return new LibnotifyNotification(delegate, this);
|
return new LibnotifyNotification(delegate, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,8 @@ class NotificationPresenterLinux : public NotificationPresenter {
|
||||||
~NotificationPresenterLinux();
|
~NotificationPresenterLinux();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Notification* CreateNotificationObject(NotificationDelegate* delegate) override;
|
Notification* CreateNotificationObject(
|
||||||
|
NotificationDelegate* delegate) override;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(NotificationPresenterLinux);
|
DISALLOW_COPY_AND_ASSIGN(NotificationPresenterLinux);
|
||||||
};
|
};
|
||||||
|
|
|
@ -22,7 +22,8 @@ class NotificationPresenterMac : public NotificationPresenter {
|
||||||
~NotificationPresenterMac();
|
~NotificationPresenterMac();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Notification* CreateNotificationObject(NotificationDelegate* delegate) override;
|
Notification* CreateNotificationObject(
|
||||||
|
NotificationDelegate* delegate) override;
|
||||||
|
|
||||||
base::scoped_nsobject<NotificationCenterDelegate>
|
base::scoped_nsobject<NotificationCenterDelegate>
|
||||||
notification_center_delegate_;
|
notification_center_delegate_;
|
||||||
|
|
|
@ -35,7 +35,8 @@ NotificationPresenterMac::~NotificationPresenterMac() {
|
||||||
NSUserNotificationCenter.defaultUserNotificationCenter.delegate = nil;
|
NSUserNotificationCenter.defaultUserNotificationCenter.delegate = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
Notification* NotificationPresenterMac::CreateNotificationObject(NotificationDelegate* delegate) {
|
Notification* NotificationPresenterMac::CreateNotificationObject(
|
||||||
|
NotificationDelegate* delegate) {
|
||||||
return new CocoaNotification(delegate, this);
|
return new CocoaNotification(delegate, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,8 @@ class NotificationPresenter {
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
NotificationPresenter();
|
NotificationPresenter();
|
||||||
virtual Notification* CreateNotificationObject(NotificationDelegate* delegate) = 0;
|
virtual Notification* CreateNotificationObject(
|
||||||
|
NotificationDelegate* delegate) = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class Notification;
|
friend class Notification;
|
||||||
|
|
|
@ -72,7 +72,8 @@ base::string16 NotificationPresenterWin::SaveIconToFilesystem(
|
||||||
return base::UTF8ToUTF16(origin.spec());
|
return base::UTF8ToUTF16(origin.spec());
|
||||||
}
|
}
|
||||||
|
|
||||||
Notification* NotificationPresenterWin::CreateNotificationObject(NotificationDelegate* delegate) {
|
Notification* NotificationPresenterWin::CreateNotificationObject(
|
||||||
|
NotificationDelegate* delegate) {
|
||||||
return new WindowsToastNotification(delegate, this);
|
return new WindowsToastNotification(delegate, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,8 @@ class NotificationPresenterWin : public NotificationPresenter {
|
||||||
base::string16 SaveIconToFilesystem(const SkBitmap& icon, const GURL& origin);
|
base::string16 SaveIconToFilesystem(const SkBitmap& icon, const GURL& origin);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Notification* CreateNotificationObject(NotificationDelegate* delegate) override;
|
Notification* CreateNotificationObject(
|
||||||
|
NotificationDelegate* delegate) override;
|
||||||
|
|
||||||
base::ScopedTempDir temp_dir_;
|
base::ScopedTempDir temp_dir_;
|
||||||
|
|
||||||
|
|
|
@ -3,12 +3,14 @@
|
||||||
|
|
||||||
namespace brightray {
|
namespace brightray {
|
||||||
|
|
||||||
brightray::Notification* NotificationPresenterWin7::CreateNotificationObject(NotificationDelegate* delegate)
|
brightray::Notification* NotificationPresenterWin7::CreateNotificationObject(
|
||||||
|
NotificationDelegate* delegate)
|
||||||
{
|
{
|
||||||
return new Win32Notification(delegate, this);
|
return new Win32Notification(delegate, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Win32Notification* NotificationPresenterWin7::GetNotificationObjectByRef(const DesktopNotificationController::Notification& ref)
|
Win32Notification* NotificationPresenterWin7::GetNotificationObjectByRef(
|
||||||
|
const DesktopNotificationController::Notification& ref)
|
||||||
{
|
{
|
||||||
for(auto n : this->notifications())
|
for(auto n : this->notifications())
|
||||||
{
|
{
|
||||||
|
@ -20,7 +22,8 @@ Win32Notification* NotificationPresenterWin7::GetNotificationObjectByRef(const D
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Win32Notification* NotificationPresenterWin7::GetNotificationObjectByTag(const std::string& tag)
|
Win32Notification* NotificationPresenterWin7::GetNotificationObjectByTag(
|
||||||
|
const std::string& tag)
|
||||||
{
|
{
|
||||||
for(auto n : this->notifications())
|
for(auto n : this->notifications())
|
||||||
{
|
{
|
||||||
|
@ -32,13 +35,15 @@ Win32Notification* NotificationPresenterWin7::GetNotificationObjectByTag(const s
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NotificationPresenterWin7::OnNotificationClicked(Notification& notification)
|
void NotificationPresenterWin7::OnNotificationClicked(
|
||||||
|
Notification& notification)
|
||||||
{
|
{
|
||||||
auto n = GetNotificationObjectByRef(notification);
|
auto n = GetNotificationObjectByRef(notification);
|
||||||
if(n) n->NotificationClicked();
|
if(n) n->NotificationClicked();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NotificationPresenterWin7::OnNotificationDismissed(Notification& notification)
|
void NotificationPresenterWin7::OnNotificationDismissed(
|
||||||
|
Notification& notification)
|
||||||
{
|
{
|
||||||
auto n = GetNotificationObjectByRef(notification);
|
auto n = GetNotificationObjectByRef(notification);
|
||||||
if(n) n->NotificationDismissed();
|
if(n) n->NotificationDismissed();
|
||||||
|
|
|
@ -13,13 +13,16 @@ class NotificationPresenterWin7 :
|
||||||
public:
|
public:
|
||||||
NotificationPresenterWin7() = default;
|
NotificationPresenterWin7() = default;
|
||||||
|
|
||||||
Win32Notification* GetNotificationObjectByRef(const DesktopNotificationController::Notification& ref);
|
Win32Notification* GetNotificationObjectByRef(
|
||||||
|
const DesktopNotificationController::Notification& ref);
|
||||||
|
|
||||||
Win32Notification* GetNotificationObjectByTag(const std::string& tag);
|
Win32Notification* GetNotificationObjectByTag(const std::string& tag);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DISALLOW_COPY_AND_ASSIGN(NotificationPresenterWin7);
|
DISALLOW_COPY_AND_ASSIGN(NotificationPresenterWin7);
|
||||||
|
|
||||||
brightray::Notification* CreateNotificationObject(NotificationDelegate* delegate) override;
|
brightray::Notification* CreateNotificationObject(
|
||||||
|
NotificationDelegate* delegate) override;
|
||||||
|
|
||||||
void OnNotificationClicked(Notification& notification) override;
|
void OnNotificationClicked(Notification& notification) override;
|
||||||
void OnNotificationDismissed(Notification& notification) override;
|
void OnNotificationDismissed(Notification& notification) override;
|
||||||
|
|
|
@ -36,7 +36,9 @@ struct ScreenMetrics
|
||||||
ScreenMetrics()
|
ScreenMetrics()
|
||||||
{
|
{
|
||||||
typedef HRESULT WINAPI GetDpiForMonitor_t(HMONITOR, int, UINT*, UINT*);
|
typedef HRESULT WINAPI GetDpiForMonitor_t(HMONITOR, int, UINT*, UINT*);
|
||||||
auto GetDpiForMonitor = (GetDpiForMonitor_t*)GetProcAddress(GetModuleHandle(TEXT("shcore")), "GetDpiForMonitor");
|
auto GetDpiForMonitor =
|
||||||
|
(GetDpiForMonitor_t*)GetProcAddress(GetModuleHandle(TEXT("shcore")),
|
||||||
|
"GetDpiForMonitor");
|
||||||
if(GetDpiForMonitor)
|
if(GetDpiForMonitor)
|
||||||
{
|
{
|
||||||
auto monitor = MonitorFromPoint({}, MONITOR_DEFAULTTOPRIMARY);
|
auto monitor = MonitorFromPoint({}, MONITOR_DEFAULTTOPRIMARY);
|
||||||
|
@ -50,8 +52,8 @@ struct ScreenMetrics
|
||||||
ReleaseDC(NULL, hdc);
|
ReleaseDC(NULL, hdc);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T> T X(T value) const { return ScaleForDpi(value, dpi_x); }
|
template<class T> T X(T value) const { return ScaleForDpi(value, dpi_x); }
|
||||||
template<typename T> T Y(T value) const { return ScaleForDpi(value, dpi_y); }
|
template<class T> T Y(T value) const { return ScaleForDpi(value, dpi_y); }
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,8 @@ HBITMAP CopyBitmap(HBITMAP bitmap)
|
||||||
HDC hdcDst = CreateCompatibleDC(NULL);
|
HDC hdcDst = CreateCompatibleDC(NULL);
|
||||||
SelectBitmap(hdcSrc, bitmap);
|
SelectBitmap(hdcSrc, bitmap);
|
||||||
SelectBitmap(hdcDst, ret);
|
SelectBitmap(hdcDst, ret);
|
||||||
BitBlt(hdcDst, 0, 0, bm.bmWidth, bm.bmHeight, hdcSrc, 0, 0, SRCCOPY);
|
BitBlt(hdcDst, 0, 0, bm.bmWidth, bm.bmHeight,
|
||||||
|
hdcSrc, 0, 0, SRCCOPY);
|
||||||
DeleteDC(hdcDst);
|
DeleteDC(hdcDst);
|
||||||
DeleteDC(hdcSrc);
|
DeleteDC(hdcSrc);
|
||||||
}
|
}
|
||||||
|
@ -40,14 +41,19 @@ HBITMAP CopyBitmap(HBITMAP bitmap)
|
||||||
HINSTANCE DesktopNotificationController::RegisterWndClasses()
|
HINSTANCE DesktopNotificationController::RegisterWndClasses()
|
||||||
{
|
{
|
||||||
// We keep a static `module` variable which serves a dual purpose:
|
// We keep a static `module` variable which serves a dual purpose:
|
||||||
// 1. Stores the HINSTANCE where the window classes are registered, which can be passed to `CreateWindow`
|
// 1. Stores the HINSTANCE where the window classes are registered,
|
||||||
// 2. Indicates whether we already attempted the registration so that we don't do it twice (we don't retry
|
// which can be passed to `CreateWindow`
|
||||||
// even if registration fails, as there is no point.
|
// 2. Indicates whether we already attempted the registration so that
|
||||||
|
// we don't do it twice (we don't retry even if registration fails,
|
||||||
|
// as there is no point).
|
||||||
static HMODULE module = NULL;
|
static HMODULE module = NULL;
|
||||||
|
|
||||||
if(!module)
|
if(!module)
|
||||||
{
|
{
|
||||||
if(GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, reinterpret_cast<LPCWSTR>(&RegisterWndClasses), &module))
|
if(GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
|
||||||
|
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
|
||||||
|
reinterpret_cast<LPCWSTR>(&RegisterWndClasses),
|
||||||
|
&module))
|
||||||
{
|
{
|
||||||
Toast::Register(module);
|
Toast::Register(module);
|
||||||
|
|
||||||
|
@ -64,7 +70,8 @@ HINSTANCE DesktopNotificationController::RegisterWndClasses()
|
||||||
return module;
|
return module;
|
||||||
}
|
}
|
||||||
|
|
||||||
DesktopNotificationController::DesktopNotificationController(unsigned maximumToasts)
|
DesktopNotificationController::DesktopNotificationController(
|
||||||
|
unsigned maximumToasts)
|
||||||
{
|
{
|
||||||
instances_.reserve(maximumToasts);
|
instances_.reserve(maximumToasts);
|
||||||
}
|
}
|
||||||
|
@ -76,7 +83,8 @@ DesktopNotificationController::~DesktopNotificationController()
|
||||||
ClearAssets();
|
ClearAssets();
|
||||||
}
|
}
|
||||||
|
|
||||||
LRESULT CALLBACK DesktopNotificationController::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
LRESULT CALLBACK DesktopNotificationController::WndProc(
|
||||||
|
HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
switch(message)
|
switch(message)
|
||||||
{
|
{
|
||||||
|
@ -119,8 +127,9 @@ void DesktopNotificationController::StartAnimation()
|
||||||
|
|
||||||
if(!is_animating_ && hwnd_controller_)
|
if(!is_animating_ && hwnd_controller_)
|
||||||
{
|
{
|
||||||
// NOTE: 15ms is shorter than what we'd need for 60 fps, but since the timer
|
// NOTE: 15ms is shorter than what we'd need for 60 fps, but since
|
||||||
// is not accurate we must request a higher frame rate to get at least 60
|
// the timer is not accurate we must request a higher frame rate
|
||||||
|
// to get at least 60
|
||||||
|
|
||||||
SetTimer(hwnd_controller_, TimerID_Animate, 15, nullptr);
|
SetTimer(hwnd_controller_, TimerID_Animate, 15, nullptr);
|
||||||
is_animating_ = true;
|
is_animating_ = true;
|
||||||
|
@ -152,11 +161,13 @@ void DesktopNotificationController::InitializeFonts()
|
||||||
auto dpiY = GetDeviceCaps(hdc, LOGPIXELSY);
|
auto dpiY = GetDeviceCaps(hdc, LOGPIXELSY);
|
||||||
ReleaseDC(NULL, hdc);
|
ReleaseDC(NULL, hdc);
|
||||||
|
|
||||||
metrics.lfMessageFont.lfHeight = (LONG)ScaleForDpi(baseHeight * 1.1f, dpiY);
|
metrics.lfMessageFont.lfHeight =
|
||||||
|
(LONG)ScaleForDpi(baseHeight * 1.1f, dpiY);
|
||||||
body_font_ = CreateFontIndirect(&metrics.lfMessageFont);
|
body_font_ = CreateFontIndirect(&metrics.lfMessageFont);
|
||||||
|
|
||||||
if(caption_font_) DeleteFont(caption_font_);
|
if(caption_font_) DeleteFont(caption_font_);
|
||||||
metrics.lfMessageFont.lfHeight = (LONG)ScaleForDpi(baseHeight * 1.4f, dpiY);
|
metrics.lfMessageFont.lfHeight =
|
||||||
|
(LONG)ScaleForDpi(baseHeight * 1.4f, dpiY);
|
||||||
caption_font_ = CreateFontIndirect(&metrics.lfMessageFont);
|
caption_font_ = CreateFontIndirect(&metrics.lfMessageFont);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -266,7 +277,9 @@ void DesktopNotificationController::AnimateAll()
|
||||||
CheckQueue();
|
CheckQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
DesktopNotificationController::Notification DesktopNotificationController::AddNotification(std::wstring caption, std::wstring bodyText, HBITMAP image)
|
DesktopNotificationController::Notification
|
||||||
|
DesktopNotificationController::AddNotification(
|
||||||
|
std::wstring caption, std::wstring bodyText, HBITMAP image)
|
||||||
{
|
{
|
||||||
NotificationLink data(this);
|
NotificationLink data(this);
|
||||||
|
|
||||||
|
@ -280,7 +293,8 @@ DesktopNotificationController::Notification DesktopNotificationController::AddNo
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DesktopNotificationController::CloseNotification(Notification& notification)
|
void DesktopNotificationController::CloseNotification(
|
||||||
|
Notification& notification)
|
||||||
{
|
{
|
||||||
// Remove it from the queue
|
// Remove it from the queue
|
||||||
auto it = find(queue_.begin(), queue_.end(), notification.data_);
|
auto it = find(queue_.begin(), queue_.end(), notification.data_);
|
||||||
|
@ -323,15 +337,20 @@ void DesktopNotificationController::CreateToast(NotificationLink&& data)
|
||||||
|
|
||||||
ScreenMetrics scr;
|
ScreenMetrics scr;
|
||||||
auto toast = Toast::Get(item.hwnd);
|
auto toast = Toast::Get(item.hwnd);
|
||||||
toastPos = toast->GetVerticalPosition() + toast->GetHeight() + scr.Y(toast_margin_<int>);
|
toastPos = toast->GetVerticalPosition() +
|
||||||
|
toast->GetHeight() +
|
||||||
|
scr.Y(toast_margin_<int>);
|
||||||
}
|
}
|
||||||
|
|
||||||
instances_.push_back({ hwnd, move(data) });
|
instances_.push_back({ hwnd, move(data) });
|
||||||
|
|
||||||
if(!hwnd_controller_)
|
if(!hwnd_controller_)
|
||||||
{
|
{
|
||||||
// NOTE: We cannot use a message-only window because we need to receive system notifications
|
// NOTE: We cannot use a message-only window because we need to
|
||||||
hwnd_controller_ = CreateWindow(class_name_, nullptr, 0, 0, 0, 0, 0, NULL, NULL, hInstance, this);
|
// receive system notifications
|
||||||
|
hwnd_controller_ = CreateWindow(class_name_, nullptr, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
NULL, NULL, hInstance, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto toast = Toast::Get(hwnd);
|
auto toast = Toast::Get(hwnd);
|
||||||
|
@ -339,9 +358,11 @@ void DesktopNotificationController::CreateToast(NotificationLink&& data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HWND DesktopNotificationController::GetToast(const NotificationData* data) const
|
HWND DesktopNotificationController::GetToast(
|
||||||
|
const NotificationData* data) const
|
||||||
{
|
{
|
||||||
auto it = find_if(instances_.cbegin(), instances_.cend(), [data](auto&& inst) {
|
auto it = find_if(instances_.cbegin(), instances_.cend(),
|
||||||
|
[data](auto&& inst) {
|
||||||
auto toast = Toast::Get(inst.hwnd);
|
auto toast = Toast::Get(inst.hwnd);
|
||||||
return data == toast->GetNotification().get();
|
return data == toast->GetNotification().get();
|
||||||
});
|
});
|
||||||
|
@ -364,13 +385,15 @@ void DesktopNotificationController::DestroyToast(ToastInstance& inst)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DesktopNotificationController::Notification::Notification(const shared_ptr<NotificationData>& data) :
|
DesktopNotificationController::Notification::Notification(
|
||||||
|
const shared_ptr<NotificationData>& data) :
|
||||||
data_(data)
|
data_(data)
|
||||||
{
|
{
|
||||||
_ASSERT(data != nullptr);
|
_ASSERT(data != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DesktopNotificationController::Notification::operator==(const Notification& other) const
|
bool DesktopNotificationController::Notification::operator==(
|
||||||
|
const Notification& other) const
|
||||||
{
|
{
|
||||||
return data_ == other.data_;
|
return data_ == other.data_;
|
||||||
}
|
}
|
||||||
|
@ -384,7 +407,8 @@ void DesktopNotificationController::Notification::Close()
|
||||||
data_->controller->CloseNotification(*this);
|
data_->controller->CloseNotification(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DesktopNotificationController::Notification::Set(std::wstring caption, std::wstring bodyText, HBITMAP image)
|
void DesktopNotificationController::Notification::Set(
|
||||||
|
std::wstring caption, std::wstring bodyText, HBITMAP image)
|
||||||
{
|
{
|
||||||
// No business calling this when not pointing to a valid instance
|
// No business calling this when not pointing to a valid instance
|
||||||
_ASSERT(data_);
|
_ASSERT(data_);
|
||||||
|
@ -411,7 +435,8 @@ void DesktopNotificationController::Notification::Set(std::wstring caption, std:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DesktopNotificationController::NotificationLink::NotificationLink(DesktopNotificationController* controller) :
|
DesktopNotificationController::NotificationLink::NotificationLink(
|
||||||
|
DesktopNotificationController* controller) :
|
||||||
shared_ptr(make_shared<NotificationData>())
|
shared_ptr(make_shared<NotificationData>())
|
||||||
{
|
{
|
||||||
get()->controller = controller;
|
get()->controller = controller;
|
||||||
|
|
|
@ -16,7 +16,8 @@ public:
|
||||||
~DesktopNotificationController();
|
~DesktopNotificationController();
|
||||||
|
|
||||||
class Notification;
|
class Notification;
|
||||||
Notification AddNotification(std::wstring caption, std::wstring bodyText, HBITMAP image);
|
Notification AddNotification(std::wstring caption, std::wstring bodyText,
|
||||||
|
HBITMAP image);
|
||||||
void CloseNotification(Notification& notification);
|
void CloseNotification(Notification& notification);
|
||||||
|
|
||||||
// Event handlers -- override to receive the events
|
// Event handlers -- override to receive the events
|
||||||
|
@ -58,13 +59,16 @@ private:
|
||||||
|
|
||||||
class Toast;
|
class Toast;
|
||||||
|
|
||||||
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
|
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message,
|
||||||
|
WPARAM wParam, LPARAM lParam);
|
||||||
static DesktopNotificationController* Get(HWND hWnd)
|
static DesktopNotificationController* Get(HWND hWnd)
|
||||||
{
|
{
|
||||||
return reinterpret_cast<DesktopNotificationController*>(GetWindowLongPtr(hWnd, 0));
|
return reinterpret_cast<DesktopNotificationController*>(
|
||||||
|
GetWindowLongPtr(hWnd, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
DesktopNotificationController(const DesktopNotificationController&) = delete;
|
DesktopNotificationController(
|
||||||
|
const DesktopNotificationController&) = delete;
|
||||||
|
|
||||||
void InitializeFonts();
|
void InitializeFonts();
|
||||||
void ClearAssets();
|
void ClearAssets();
|
||||||
|
@ -75,7 +79,9 @@ private:
|
||||||
void DestroyToast(ToastInstance& inst);
|
void DestroyToast(ToastInstance& inst);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr const TCHAR class_name_[] = TEXT("DesktopNotificationController");
|
static constexpr const TCHAR class_name_[] =
|
||||||
|
TEXT("DesktopNotificationController");
|
||||||
|
|
||||||
HWND hwnd_controller_ = NULL;
|
HWND hwnd_controller_ = NULL;
|
||||||
HFONT caption_font_ = NULL, body_font_ = NULL;
|
HFONT caption_font_ = NULL, body_font_ = NULL;
|
||||||
std::vector<ToastInstance> instances_;
|
std::vector<ToastInstance> instances_;
|
||||||
|
|
|
@ -18,20 +18,34 @@ static COLORREF GetAccentColor()
|
||||||
if(IsAppThemed())
|
if(IsAppThemed())
|
||||||
{
|
{
|
||||||
HKEY hkey;
|
HKEY hkey;
|
||||||
if(RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\Windows\\DWM"), 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)
|
if(RegOpenKeyEx(HKEY_CURRENT_USER,
|
||||||
|
TEXT("SOFTWARE\\Microsoft\\Windows\\DWM"), 0,
|
||||||
|
KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
COLORREF color;
|
COLORREF color;
|
||||||
DWORD type, size;
|
DWORD type, size;
|
||||||
if(RegQueryValueEx(hkey, TEXT("AccentColor"), nullptr, &type, (BYTE*)&color, &(size = sizeof(color))) == ERROR_SUCCESS && type == REG_DWORD)
|
if(RegQueryValueEx(hkey, TEXT("AccentColor"), nullptr,
|
||||||
|
&type,
|
||||||
|
(BYTE*)&color,
|
||||||
|
&(size = sizeof(color))) == ERROR_SUCCESS &&
|
||||||
|
type == REG_DWORD)
|
||||||
{
|
{
|
||||||
// convert from RGBA
|
// convert from RGBA
|
||||||
color = RGB(GetRValue(color), GetGValue(color), GetBValue(color));
|
color = RGB(GetRValue(color),
|
||||||
|
GetGValue(color),
|
||||||
|
GetBValue(color));
|
||||||
success = true;
|
success = true;
|
||||||
}
|
}
|
||||||
else if(RegQueryValueEx(hkey, TEXT("ColorizationColor"), nullptr, &type, (BYTE*)&color, &(size = sizeof(color))) == ERROR_SUCCESS && type == REG_DWORD)
|
else if(RegQueryValueEx(hkey, TEXT("ColorizationColor"), nullptr,
|
||||||
|
&type,
|
||||||
|
(BYTE*)&color,
|
||||||
|
&(size = sizeof(color))) == ERROR_SUCCESS &&
|
||||||
|
type == REG_DWORD)
|
||||||
{
|
{
|
||||||
// convert from BGRA
|
// convert from BGRA
|
||||||
color = RGB(GetBValue(color), GetGValue(color), GetRValue(color));
|
color = RGB(GetBValue(color),
|
||||||
|
GetGValue(color),
|
||||||
|
GetRValue(color));
|
||||||
success = true;
|
success = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,8 +62,8 @@ static COLORREF GetAccentColor()
|
||||||
static HBITMAP StretchBitmap(HBITMAP bitmap, unsigned width, unsigned height)
|
static HBITMAP StretchBitmap(HBITMAP bitmap, unsigned width, unsigned height)
|
||||||
{
|
{
|
||||||
// We use StretchBlt for the scaling, but that discards the alpha channel.
|
// We use StretchBlt for the scaling, but that discards the alpha channel.
|
||||||
// Therefore we first create a separate grayscale bitmap from the alpha channel,
|
// So we first create a separate grayscale bitmap from the alpha channel,
|
||||||
// scale that separately and copy it back to the scaled color bitmap.
|
// scale that separately, and copy it back to the scaled color bitmap.
|
||||||
|
|
||||||
BITMAP bm;
|
BITMAP bm;
|
||||||
if(!GetObject(bitmap, sizeof(bm), &bm))
|
if(!GetObject(bitmap, sizeof(bm), &bm))
|
||||||
|
@ -72,21 +86,27 @@ static HBITMAP StretchBitmap(HBITMAP bitmap, unsigned width, unsigned height)
|
||||||
bmi.biCompression = BI_RGB;
|
bmi.biCompression = BI_RGB;
|
||||||
|
|
||||||
void* alphaSrcBits;
|
void* alphaSrcBits;
|
||||||
alphaSrcBitmap = CreateDIBSection(NULL, (BITMAPINFO*)&bmi, DIB_RGB_COLORS, &alphaSrcBits, NULL, 0);
|
alphaSrcBitmap = CreateDIBSection(NULL, (BITMAPINFO*)&bmi,
|
||||||
|
DIB_RGB_COLORS, &alphaSrcBits,
|
||||||
|
NULL, 0);
|
||||||
|
|
||||||
if(alphaSrcBitmap)
|
if(alphaSrcBitmap)
|
||||||
{
|
{
|
||||||
if(GetDIBits(hdcScreen, bitmap, 0, 0, 0, (BITMAPINFO*)&bmi, DIB_RGB_COLORS) &&
|
if(GetDIBits(hdcScreen, bitmap, 0, 0, 0,
|
||||||
|
(BITMAPINFO*)&bmi, DIB_RGB_COLORS) &&
|
||||||
bmi.biSizeImage > 0 &&
|
bmi.biSizeImage > 0 &&
|
||||||
(bmi.biSizeImage % 4) == 0)
|
(bmi.biSizeImage % 4) == 0)
|
||||||
{
|
{
|
||||||
auto buf = (DWORD*)_aligned_malloc(bmi.biSizeImage, sizeof(DWORD));
|
auto buf = (BYTE*)_aligned_malloc(bmi.biSizeImage,
|
||||||
|
sizeof(DWORD));
|
||||||
if(buf)
|
if(buf)
|
||||||
{
|
{
|
||||||
GetDIBits(hdcScreen, bitmap, 0, bm.bmHeight, buf, (BITMAPINFO*)&bmi, DIB_RGB_COLORS);
|
GetDIBits(hdcScreen, bitmap, 0, bm.bmHeight, buf,
|
||||||
|
(BITMAPINFO*)&bmi, DIB_RGB_COLORS);
|
||||||
|
|
||||||
BYTE* dest = (BYTE*)alphaSrcBits;
|
BYTE* dest = (BYTE*)alphaSrcBits;
|
||||||
for(const DWORD *src = buf, *end = (DWORD*)((BYTE*)buf + bmi.biSizeImage);
|
for(const DWORD *src = (DWORD*)buf,
|
||||||
|
*end = (DWORD*)(buf + bmi.biSizeImage);
|
||||||
src != end;
|
src != end;
|
||||||
++src, ++dest)
|
++src, ++dest)
|
||||||
{
|
{
|
||||||
|
@ -112,10 +132,14 @@ static HBITMAP StretchBitmap(HBITMAP bitmap, unsigned width, unsigned height)
|
||||||
bmi.biCompression = BI_RGB;
|
bmi.biCompression = BI_RGB;
|
||||||
|
|
||||||
void* colorBits;
|
void* colorBits;
|
||||||
auto colorBitmap = CreateDIBSection(NULL, (BITMAPINFO*)&bmi, DIB_RGB_COLORS, &colorBits, NULL, 0);
|
auto colorBitmap = CreateDIBSection(NULL, (BITMAPINFO*)&bmi,
|
||||||
|
DIB_RGB_COLORS, &colorBits,
|
||||||
|
NULL, 0);
|
||||||
|
|
||||||
void* alphaBits;
|
void* alphaBits;
|
||||||
auto alphaBitmap = CreateDIBSection(NULL, (BITMAPINFO*)&bmi, DIB_RGB_COLORS, &alphaBits, NULL, 0);
|
auto alphaBitmap = CreateDIBSection(NULL, (BITMAPINFO*)&bmi,
|
||||||
|
DIB_RGB_COLORS, &alphaBits,
|
||||||
|
NULL, 0);
|
||||||
|
|
||||||
HDC hdc = CreateCompatibleDC(NULL);
|
HDC hdc = CreateCompatibleDC(NULL);
|
||||||
HDC hdcSrc = CreateCompatibleDC(NULL);
|
HDC hdcSrc = CreateCompatibleDC(NULL);
|
||||||
|
@ -127,12 +151,16 @@ static HBITMAP StretchBitmap(HBITMAP bitmap, unsigned width, unsigned height)
|
||||||
// resize color channels
|
// resize color channels
|
||||||
SelectObject(hdc, colorBitmap);
|
SelectObject(hdc, colorBitmap);
|
||||||
SelectObject(hdcSrc, bitmap);
|
SelectObject(hdcSrc, bitmap);
|
||||||
StretchBlt(hdc, 0, 0, width, height, hdcSrc, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
|
StretchBlt(hdc, 0, 0, width, height,
|
||||||
|
hdcSrc, 0, 0, bm.bmWidth, bm.bmHeight,
|
||||||
|
SRCCOPY);
|
||||||
|
|
||||||
// resize alpha channel
|
// resize alpha channel
|
||||||
SelectObject(hdc, alphaBitmap);
|
SelectObject(hdc, alphaBitmap);
|
||||||
SelectObject(hdcSrc, alphaSrcBitmap);
|
SelectObject(hdcSrc, alphaSrcBitmap);
|
||||||
StretchBlt(hdc, 0, 0, width, height, hdcSrc, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
|
StretchBlt(hdc, 0, 0, width, height,
|
||||||
|
hdcSrc, 0, 0, bm.bmWidth, bm.bmHeight,
|
||||||
|
SRCCOPY);
|
||||||
|
|
||||||
// flush before touching the bits
|
// flush before touching the bits
|
||||||
GdiFlush();
|
GdiFlush();
|
||||||
|
@ -149,7 +177,9 @@ static HBITMAP StretchBitmap(HBITMAP bitmap, unsigned width, unsigned height)
|
||||||
}
|
}
|
||||||
|
|
||||||
// create the resulting bitmap
|
// create the resulting bitmap
|
||||||
resultBitmap = CreateDIBitmap(hdcScreen, &bmi, CBM_INIT, colorBits, (BITMAPINFO*)&bmi, DIB_RGB_COLORS);
|
resultBitmap = CreateDIBitmap(hdcScreen, &bmi, CBM_INIT,
|
||||||
|
colorBits, (BITMAPINFO*)&bmi,
|
||||||
|
DIB_RGB_COLORS);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(hdcSrc) DeleteDC(hdcSrc);
|
if(hdcSrc) DeleteDC(hdcSrc);
|
||||||
|
@ -166,7 +196,8 @@ static HBITMAP StretchBitmap(HBITMAP bitmap, unsigned width, unsigned height)
|
||||||
return resultBitmap;
|
return resultBitmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
DesktopNotificationController::Toast::Toast(HWND hWnd, shared_ptr<NotificationData>* data) :
|
DesktopNotificationController::Toast::Toast(
|
||||||
|
HWND hWnd, shared_ptr<NotificationData>* data) :
|
||||||
hwnd_(hWnd), data_(*data)
|
hwnd_(hWnd), data_(*data)
|
||||||
{
|
{
|
||||||
HDC hdcScreen = GetDC(NULL);
|
HDC hdcScreen = GetDC(NULL);
|
||||||
|
@ -193,14 +224,17 @@ void DesktopNotificationController::Toast::Register(HINSTANCE hInstance)
|
||||||
RegisterClassEx(&wc);
|
RegisterClassEx(&wc);
|
||||||
}
|
}
|
||||||
|
|
||||||
LRESULT DesktopNotificationController::Toast::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
LRESULT DesktopNotificationController::Toast::WndProc(
|
||||||
|
HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
switch(message)
|
switch(message)
|
||||||
{
|
{
|
||||||
case WM_CREATE:
|
case WM_CREATE:
|
||||||
{
|
{
|
||||||
auto& cs = reinterpret_cast<const CREATESTRUCT*&>(lParam);
|
auto& cs = reinterpret_cast<const CREATESTRUCT*&>(lParam);
|
||||||
auto inst = new Toast(hWnd, static_cast<shared_ptr<NotificationData>*>(cs->lpCreateParams));
|
auto data =
|
||||||
|
static_cast<shared_ptr<NotificationData>*>(cs->lpCreateParams);
|
||||||
|
auto inst = new Toast(hWnd, data);
|
||||||
SetWindowLongPtr(hWnd, 0, (LONG_PTR)inst);
|
SetWindowLongPtr(hWnd, 0, (LONG_PTR)inst);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -246,7 +280,8 @@ LRESULT DesktopNotificationController::Toast::WndProc(HWND hWnd, UINT message, W
|
||||||
}
|
}
|
||||||
|
|
||||||
POINT cursor = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
|
POINT cursor = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
|
||||||
inst->is_close_hot_ = (PtInRect(&inst->close_button_rect_, cursor) != FALSE);
|
inst->is_close_hot_ =
|
||||||
|
(PtInRect(&inst->close_button_rect_, cursor) != FALSE);
|
||||||
|
|
||||||
if(!inst->is_non_interactive_)
|
if(!inst->is_non_interactive_)
|
||||||
inst->CancelDismiss();
|
inst->CancelDismiss();
|
||||||
|
@ -285,9 +320,12 @@ LRESULT DesktopNotificationController::Toast::WndProc(HWND hWnd, UINT message, W
|
||||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
HWND DesktopNotificationController::Toast::Create(HINSTANCE hInstance, shared_ptr<NotificationData>& data)
|
HWND DesktopNotificationController::Toast::Create(
|
||||||
|
HINSTANCE hInstance, shared_ptr<NotificationData>& data)
|
||||||
{
|
{
|
||||||
return CreateWindowEx(WS_EX_LAYERED | WS_EX_NOACTIVATE | WS_EX_TOPMOST, class_name_, nullptr, WS_POPUP, 0, 0, 0, 0, NULL, NULL, hInstance, &data);
|
return CreateWindowEx(WS_EX_LAYERED | WS_EX_NOACTIVATE | WS_EX_TOPMOST,
|
||||||
|
class_name_, nullptr, WS_POPUP, 0, 0, 0, 0,
|
||||||
|
NULL, NULL, hInstance, &data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DesktopNotificationController::Toast::Draw()
|
void DesktopNotificationController::Toast::Draw()
|
||||||
|
@ -319,9 +357,9 @@ void DesktopNotificationController::Toast::Draw()
|
||||||
|
|
||||||
COLORREF foreColor, dimmedColor;
|
COLORREF foreColor, dimmedColor;
|
||||||
{
|
{
|
||||||
// based on the lightness of background, we draw foreground in light or dark
|
// based on the lightness of background, we draw foreground in light
|
||||||
// shades of gray blended onto the background with slight transparency
|
// or dark shades of gray blended onto the background with slight
|
||||||
// to avoid sharp contrast
|
// transparency to avoid sharp contrast
|
||||||
|
|
||||||
constexpr float alpha = 0.9f;
|
constexpr float alpha = 0.9f;
|
||||||
constexpr float intensityLight[] = { (1.0f * alpha), (0.8f * alpha) };
|
constexpr float intensityLight[] = { (1.0f * alpha), (0.8f * alpha) };
|
||||||
|
@ -395,7 +433,11 @@ void DesktopNotificationController::Toast::Draw()
|
||||||
HDC hdcImage = CreateCompatibleDC(NULL);
|
HDC hdcImage = CreateCompatibleDC(NULL);
|
||||||
SelectBitmap(hdcImage, scaled_image_);
|
SelectBitmap(hdcImage, scaled_image_);
|
||||||
BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
|
BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
|
||||||
AlphaBlend(hdc_, margin_.cx, margin_.cy, imageInfo.bmWidth, imageInfo.bmHeight, hdcImage, 0, 0, imageInfo.bmWidth, imageInfo.bmHeight, blend);
|
AlphaBlend(hdc_, margin_.cx, margin_.cy,
|
||||||
|
imageInfo.bmWidth, imageInfo.bmHeight,
|
||||||
|
hdcImage, 0, 0,
|
||||||
|
imageInfo.bmWidth, imageInfo.bmHeight,
|
||||||
|
blend);
|
||||||
DeleteDC(hdcImage);
|
DeleteDC(hdcImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -410,7 +452,8 @@ void DesktopNotificationController::Toast::Draw()
|
||||||
|
|
||||||
SelectFont(hdc_, captionFont);
|
SelectFont(hdc_, captionFont);
|
||||||
SetTextColor(hdc_, foreColor);
|
SetTextColor(hdc_, foreColor);
|
||||||
DrawText(hdc_, data_->caption.data(), (UINT)data_->caption.length(), &rc, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX);
|
DrawText(hdc_, data_->caption.data(), (UINT)data_->caption.length(),
|
||||||
|
&rc, DT_SINGLELINE | DT_END_ELLIPSIS | DT_NOPREFIX);
|
||||||
}
|
}
|
||||||
|
|
||||||
// body text
|
// body text
|
||||||
|
@ -425,14 +468,18 @@ void DesktopNotificationController::Toast::Draw()
|
||||||
|
|
||||||
SelectFont(hdc_, bodyFont);
|
SelectFont(hdc_, bodyFont);
|
||||||
SetTextColor(hdc_, dimmedColor);
|
SetTextColor(hdc_, dimmedColor);
|
||||||
DrawText(hdc_, data_->body_text.data(), (UINT)data_->body_text.length(), &rc, DT_LEFT | DT_WORDBREAK | DT_NOPREFIX | DT_END_ELLIPSIS | DT_EDITCONTROL);
|
DrawText(hdc_, data_->body_text.data(), (UINT)data_->body_text.length(),
|
||||||
|
&rc,
|
||||||
|
DT_LEFT | DT_WORDBREAK | DT_NOPREFIX |
|
||||||
|
DT_END_ELLIPSIS | DT_EDITCONTROL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// close button
|
// close button
|
||||||
{
|
{
|
||||||
SelectFont(hdc_, captionFont);
|
SelectFont(hdc_, captionFont);
|
||||||
SetTextColor(hdc_, is_close_hot_ ? foreColor : dimmedColor);
|
SetTextColor(hdc_, is_close_hot_ ? foreColor : dimmedColor);
|
||||||
ExtTextOut(hdc_, closePos.x, closePos.y, 0, nullptr, &close, 1, nullptr);
|
ExtTextOut(hdc_, closePos.x, closePos.y, 0, nullptr,
|
||||||
|
&close, 1, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
is_content_updated_ = true;
|
is_content_updated_ = true;
|
||||||
|
@ -510,18 +557,22 @@ void DesktopNotificationController::Toast::UpdateBufferSize()
|
||||||
|
|
||||||
newSize.cx += imageDrawSize.cx + margin_.cx;
|
newSize.cx += imageDrawSize.cx + margin_.cx;
|
||||||
|
|
||||||
auto heightWithImage = margin_.cy + (imageDrawSize.cy) + margin_.cy;
|
auto heightWithImage =
|
||||||
if(newSize.cy < heightWithImage) newSize.cy = heightWithImage;
|
margin_.cy + (imageDrawSize.cy) + margin_.cy;
|
||||||
|
if(newSize.cy < heightWithImage)
|
||||||
|
newSize.cy = heightWithImage;
|
||||||
|
|
||||||
UpdateScaledImage(imageDrawSize);
|
UpdateScaledImage(imageDrawSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(newSize.cx != this->toast_size_.cx || newSize.cy != this->toast_size_.cy)
|
if(newSize.cx != this->toast_size_.cx ||
|
||||||
|
newSize.cy != this->toast_size_.cy)
|
||||||
{
|
{
|
||||||
HDC hdcScreen = GetDC(NULL);
|
HDC hdcScreen = GetDC(NULL);
|
||||||
auto newBitmap = CreateCompatibleBitmap(hdcScreen, newSize.cx, newSize.cy);
|
auto newBitmap = CreateCompatibleBitmap(hdcScreen,
|
||||||
|
newSize.cx, newSize.cy);
|
||||||
ReleaseDC(NULL, hdcScreen);
|
ReleaseDC(NULL, hdcScreen);
|
||||||
|
|
||||||
if(newBitmap)
|
if(newBitmap)
|
||||||
|
@ -529,8 +580,16 @@ void DesktopNotificationController::Toast::UpdateBufferSize()
|
||||||
if(SelectBitmap(hdc_, newBitmap))
|
if(SelectBitmap(hdc_, newBitmap))
|
||||||
{
|
{
|
||||||
RECT dirty1 = {}, dirty2 = {};
|
RECT dirty1 = {}, dirty2 = {};
|
||||||
if(toast_size_.cx < newSize.cx) dirty1 = { toast_size_.cx, 0, newSize.cx, toast_size_.cy };
|
if(toast_size_.cx < newSize.cx)
|
||||||
if(toast_size_.cy < newSize.cy) dirty2 = { 0, toast_size_.cy, newSize.cx, newSize.cy };
|
{
|
||||||
|
dirty1 = { toast_size_.cx, 0,
|
||||||
|
newSize.cx, toast_size_.cy };
|
||||||
|
}
|
||||||
|
if(toast_size_.cy < newSize.cy)
|
||||||
|
{
|
||||||
|
dirty2 = { 0, toast_size_.cy,
|
||||||
|
newSize.cx, newSize.cy };
|
||||||
|
}
|
||||||
|
|
||||||
if(this->bitmap_) DeleteBitmap(this->bitmap_);
|
if(this->bitmap_) DeleteBitmap(this->bitmap_);
|
||||||
this->bitmap_ = newBitmap;
|
this->bitmap_ = newBitmap;
|
||||||
|
@ -538,8 +597,9 @@ void DesktopNotificationController::Toast::UpdateBufferSize()
|
||||||
|
|
||||||
Invalidate();
|
Invalidate();
|
||||||
|
|
||||||
// Resize also the DWM buffer to prevent flicker during window resizing.
|
// Resize also the DWM buffer to prevent flicker during
|
||||||
// Make sure any existing data is not overwritten by marking the dirty region.
|
// window resizing. Make sure any existing data is not
|
||||||
|
// overwritten by marking the dirty region.
|
||||||
{
|
{
|
||||||
POINT origin = { 0, 0 };
|
POINT origin = { 0, 0 };
|
||||||
|
|
||||||
|
@ -591,7 +651,8 @@ void DesktopNotificationController::Toast::UpdateContents()
|
||||||
GetWindowRect(hwnd_, &rc);
|
GetWindowRect(hwnd_, &rc);
|
||||||
POINT origin = { 0, 0 };
|
POINT origin = { 0, 0 };
|
||||||
SIZE size = { rc.right - rc.left, rc.bottom - rc.top };
|
SIZE size = { rc.right - rc.left, rc.bottom - rc.top };
|
||||||
UpdateLayeredWindow(hwnd_, NULL, nullptr, &size, hdc_, &origin, 0, nullptr, 0);
|
UpdateLayeredWindow(hwnd_, NULL, nullptr, &size,
|
||||||
|
hdc_, &origin, 0, nullptr, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -599,9 +660,9 @@ void DesktopNotificationController::Toast::Dismiss()
|
||||||
{
|
{
|
||||||
if(!is_non_interactive_)
|
if(!is_non_interactive_)
|
||||||
{
|
{
|
||||||
// Set a flag to prevent further interaction. We don't disable the HWND because
|
// Set a flag to prevent further interaction. We don't disable the HWND
|
||||||
// we still want to receive mouse move messages in order to keep the toast under
|
// because we still want to receive mouse move messages in order to keep
|
||||||
// the cursor and not collapse it while dismissing.
|
// the toast under the cursor and not collapse it while dismissing.
|
||||||
is_non_interactive_ = true;
|
is_non_interactive_ = true;
|
||||||
|
|
||||||
AutoDismiss();
|
AutoDismiss();
|
||||||
|
@ -650,7 +711,8 @@ void DesktopNotificationController::Toast::SetVerticalPosition(int y)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Make sure the new animation's origin is at the current position
|
// Make sure the new animation's origin is at the current position
|
||||||
vertical_pos_ += (int)((vertical_pos_target_ - vertical_pos_) * stack_collapse_pos_);
|
vertical_pos_ +=
|
||||||
|
(int)((vertical_pos_target_ - vertical_pos_) * stack_collapse_pos_);
|
||||||
|
|
||||||
// Set new target position and start the animation
|
// Set new target position and start the animation
|
||||||
vertical_pos_target_ = y;
|
vertical_pos_target_ = y;
|
||||||
|
@ -658,7 +720,8 @@ void DesktopNotificationController::Toast::SetVerticalPosition(int y)
|
||||||
data_->controller->StartAnimation();
|
data_->controller->StartAnimation();
|
||||||
}
|
}
|
||||||
|
|
||||||
HDWP DesktopNotificationController::Toast::Animate(HDWP hdwp, const POINT& origin)
|
HDWP DesktopNotificationController::Toast::Animate(
|
||||||
|
HDWP hdwp, const POINT& origin)
|
||||||
{
|
{
|
||||||
UpdateBufferSize();
|
UpdateBufferSize();
|
||||||
|
|
||||||
|
@ -682,7 +745,8 @@ HDWP DesktopNotificationController::Toast::Animate(HDWP hdwp, const POINT& origi
|
||||||
POINT pt = { 0, 0 };
|
POINT pt = { 0, 0 };
|
||||||
SIZE size = { 0, 0 };
|
SIZE size = { 0, 0 };
|
||||||
BLENDFUNCTION blend;
|
BLENDFUNCTION blend;
|
||||||
UINT dwpFlags = SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOREDRAW | SWP_NOCOPYBITS;
|
UINT dwpFlags = SWP_NOACTIVATE | SWP_SHOWWINDOW |
|
||||||
|
SWP_NOREDRAW | SWP_NOCOPYBITS;
|
||||||
|
|
||||||
auto easeInPos = AnimateEaseIn();
|
auto easeInPos = AnimateEaseIn();
|
||||||
auto easeOutPos = AnimateEaseOut();
|
auto easeOutPos = AnimateEaseOut();
|
||||||
|
@ -735,11 +799,13 @@ HDWP DesktopNotificationController::Toast::Animate(HDWP hdwp, const POINT& origi
|
||||||
}
|
}
|
||||||
|
|
||||||
// `UpdateLayeredWindowIndirect` updates position, size, and transparency.
|
// `UpdateLayeredWindowIndirect` updates position, size, and transparency.
|
||||||
// `DeferWindowPos` updates z-order, and also position and size in case ULWI fails,
|
// `DeferWindowPos` updates z-order, and also position and size in case
|
||||||
// which can happen when one of the dimensions is zero (e.g. at the beginning of ease-in).
|
// ULWI fails, which can happen when one of the dimensions is zero (e.g.
|
||||||
|
// at the beginning of ease-in).
|
||||||
|
|
||||||
auto ulwResult = UpdateLayeredWindowIndirect(hwnd_, &ulw);
|
auto ulwResult = UpdateLayeredWindowIndirect(hwnd_, &ulw);
|
||||||
hdwp = DeferWindowPos(hdwp, hwnd_, HWND_TOPMOST, pt.x, pt.y, size.cx, size.cy, dwpFlags);
|
hdwp = DeferWindowPos(hdwp, hwnd_, HWND_TOPMOST,
|
||||||
|
pt.x, pt.y, size.cx, size.cy, dwpFlags);
|
||||||
return hdwp;
|
return hdwp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -770,7 +836,8 @@ float DesktopNotificationController::Toast::AnimateEaseIn()
|
||||||
return ease_in_pos_;
|
return ease_in_pos_;
|
||||||
|
|
||||||
constexpr float duration = 500.0f;
|
constexpr float duration = 500.0f;
|
||||||
float time = std::min(duration, (float)(GetTickCount() - ease_in_start_)) / duration;
|
float elapsed = GetTickCount() - ease_in_start_;
|
||||||
|
float time = std::min(duration, elapsed) / duration;
|
||||||
|
|
||||||
// decelerating exponential ease
|
// decelerating exponential ease
|
||||||
const float a = -8.0f;
|
const float a = -8.0f;
|
||||||
|
@ -785,7 +852,8 @@ float DesktopNotificationController::Toast::AnimateEaseOut()
|
||||||
return ease_out_pos_;
|
return ease_out_pos_;
|
||||||
|
|
||||||
constexpr float duration = 120.0f;
|
constexpr float duration = 120.0f;
|
||||||
float time = std::min(duration, (float)(GetTickCount() - ease_out_start_)) / duration;
|
float elapsed = GetTickCount() - ease_out_start_;
|
||||||
|
float time = std::min(duration, elapsed) / duration;
|
||||||
|
|
||||||
// accelerating circle ease
|
// accelerating circle ease
|
||||||
auto pos = 1.0f - std::sqrt(1 - time * time);
|
auto pos = 1.0f - std::sqrt(1 - time * time);
|
||||||
|
@ -799,7 +867,8 @@ float DesktopNotificationController::Toast::AnimateStackCollapse()
|
||||||
return stack_collapse_pos_;
|
return stack_collapse_pos_;
|
||||||
|
|
||||||
constexpr float duration = 500.0f;
|
constexpr float duration = 500.0f;
|
||||||
float time = std::min(duration, (float)(GetTickCount() - stack_collapse_start_)) / duration;
|
float elapsed = GetTickCount() - stack_collapse_start_;
|
||||||
|
float time = std::min(duration, elapsed) / duration;
|
||||||
|
|
||||||
// decelerating exponential ease
|
// decelerating exponential ease
|
||||||
const float a = -8.0f;
|
const float a = -8.0f;
|
||||||
|
|
|
@ -7,13 +7,15 @@ class DesktopNotificationController::Toast
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static void Register(HINSTANCE hInstance);
|
static void Register(HINSTANCE hInstance);
|
||||||
static HWND Create(HINSTANCE hInstance, std::shared_ptr<NotificationData>& data);
|
static HWND Create(HINSTANCE hInstance,
|
||||||
|
std::shared_ptr<NotificationData>& data);
|
||||||
static Toast* Get(HWND hWnd)
|
static Toast* Get(HWND hWnd)
|
||||||
{
|
{
|
||||||
return reinterpret_cast<Toast*>(GetWindowLongPtr(hWnd, 0));
|
return reinterpret_cast<Toast*>(GetWindowLongPtr(hWnd, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
|
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message,
|
||||||
|
WPARAM wParam, LPARAM lParam);
|
||||||
|
|
||||||
const std::shared_ptr<NotificationData>& GetNotification() const
|
const std::shared_ptr<NotificationData>& GetNotification() const
|
||||||
{
|
{
|
||||||
|
@ -73,7 +75,8 @@ private:
|
||||||
float AnimateStackCollapse();
|
float AnimateStackCollapse();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr const TCHAR class_name_[] = TEXT("DesktopNotificationToast");
|
static constexpr const TCHAR class_name_[] =
|
||||||
|
TEXT("DesktopNotificationToast");
|
||||||
|
|
||||||
const HWND hwnd_;
|
const HWND hwnd_;
|
||||||
HDC hdc_;
|
HDC hdc_;
|
||||||
|
@ -91,7 +94,9 @@ private:
|
||||||
bool is_non_interactive_ = false;
|
bool is_non_interactive_ = false;
|
||||||
bool ease_in_active_ = false;
|
bool ease_in_active_ = false;
|
||||||
bool ease_out_active_ = false;
|
bool ease_out_active_ = false;
|
||||||
bool is_content_updated_ = false, is_highlighted_ = false, is_close_hot_ = false;
|
bool is_content_updated_ = false;
|
||||||
|
bool is_highlighted_ = false;
|
||||||
|
bool is_close_hot_ = false;
|
||||||
DWORD ease_in_start_, ease_out_start_, stack_collapse_start_;
|
DWORD ease_in_start_, ease_out_start_, stack_collapse_start_;
|
||||||
float ease_in_pos_ = 0, ease_out_pos_ = 0, stack_collapse_pos_ = 0;
|
float ease_in_pos_ = 0, ease_out_pos_ = 0, stack_collapse_pos_ = 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,7 +5,10 @@
|
||||||
|
|
||||||
namespace brightray {
|
namespace brightray {
|
||||||
|
|
||||||
void Win32Notification::Show(const base::string16& title, const base::string16& msg, const std::string& tag, const GURL& icon_url, const SkBitmap& icon, const bool silent)
|
void Win32Notification::Show(
|
||||||
|
const base::string16& title, const base::string16& msg,
|
||||||
|
const std::string& tag, const GURL& icon_url,
|
||||||
|
const SkBitmap& icon, const bool silent)
|
||||||
{
|
{
|
||||||
auto presenter = static_cast<NotificationPresenterWin7*>(this->presenter());
|
auto presenter = static_cast<NotificationPresenterWin7*>(this->presenter());
|
||||||
if(!presenter) return;
|
if(!presenter) return;
|
||||||
|
@ -26,7 +29,8 @@ void Win32Notification::Show(const base::string16& title, const base::string16&
|
||||||
bmi.biCompression = BI_RGB;
|
bmi.biCompression = BI_RGB;
|
||||||
|
|
||||||
HDC hdcScreen = GetDC(NULL);
|
HDC hdcScreen = GetDC(NULL);
|
||||||
image = CreateDIBitmap(hdcScreen, &bmi, CBM_INIT, icon.getPixels(), (BITMAPINFO*)&bmi, DIB_RGB_COLORS);
|
image = CreateDIBitmap(hdcScreen, &bmi, CBM_INIT, icon.getPixels(),
|
||||||
|
(BITMAPINFO*)&bmi, DIB_RGB_COLORS);
|
||||||
ReleaseDC(NULL, hdcScreen);
|
ReleaseDC(NULL, hdcScreen);
|
||||||
|
|
||||||
icon.unlockPixels();
|
icon.unlockPixels();
|
||||||
|
|
|
@ -7,8 +7,14 @@ namespace brightray {
|
||||||
class Win32Notification : public brightray::Notification
|
class Win32Notification : public brightray::Notification
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Win32Notification(NotificationDelegate* delegate, NotificationPresenterWin7* presenter) : Notification(delegate, presenter) {}
|
Win32Notification(NotificationDelegate* delegate,
|
||||||
void Show(const base::string16& title, const base::string16& msg, const std::string& tag, const GURL& icon_url, const SkBitmap& icon, const bool silent) override;
|
NotificationPresenterWin7* presenter) :
|
||||||
|
Notification(delegate, presenter)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void Show(const base::string16& title, const base::string16& msg,
|
||||||
|
const std::string& tag, const GURL& icon_url,
|
||||||
|
const SkBitmap& icon, const bool silent) override;
|
||||||
void Dismiss() override;
|
void Dismiss() override;
|
||||||
|
|
||||||
const DesktopNotificationController::Notification& GetRef() const
|
const DesktopNotificationController::Notification& GetRef() const
|
||||||
|
|
Loading…
Reference in a new issue