mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-06-05 22:54:17 -04:00
Windows: Enable popup OS notifications even when system tray icon is disabled
Dont go through Qt's horrible system tray based notifier which in turn goes through the legacy Shell_NotifyIcon API. Instead talk to the underlying windows toast notification API directly.
This commit is contained in:
parent
16c9343bcf
commit
7fee97c627
@ -322,7 +322,7 @@ def init_env(debug=False, sanitize=False, compiling_for='native'):
|
||||
splat = '.build-cache/xwin/root'
|
||||
cflags.append('-fcolor-diagnostics')
|
||||
cflags.append('-fansi-escape-codes')
|
||||
for I in 'sdk/include/um sdk/include/cppwinrt sdk/include/shared sdk/include/ucrt crt/include'.split():
|
||||
for I in 'sdk/include/um sdk/include/cppwinrt sdk/include/shared sdk/include/ucrt crt/include sdk/include/winrt'.split():
|
||||
cflags.append('/external:I')
|
||||
cflags.append(f'{splat}/{I}')
|
||||
for L in 'sdk/lib/um crt/lib sdk/lib/ucrt'.split():
|
||||
|
@ -204,6 +204,16 @@
|
||||
"libraries": "Gdi32 User32",
|
||||
"cflags": "/X"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "wintoast",
|
||||
"only": "windows",
|
||||
"headers": "calibre/utils/cpp_binding.h calibre/utils/windows/common.h calibre/utils/windows/wintoastlib.h",
|
||||
"sources": "calibre/utils/windows/wintoastlib.cpp calibre/utils/windows/wintoast.cpp",
|
||||
"libraries": "shell32",
|
||||
"cflags": "/X"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "usbobserver",
|
||||
"only": "macos",
|
||||
|
@ -277,7 +277,7 @@ class ExtensionsImporter:
|
||||
'uchardet',
|
||||
)
|
||||
if iswindows:
|
||||
extra = ('winutil', 'wpd', 'winfonts',)
|
||||
extra = ('winutil', 'wpd', 'winfonts', 'wintoast')
|
||||
elif ismacos:
|
||||
extra = ('usbobserver', 'cocoa', 'libusb', 'libmtp')
|
||||
elif isfreebsd or ishaiku or islinux:
|
||||
|
@ -10,7 +10,7 @@ import sys
|
||||
from contextlib import suppress
|
||||
from functools import lru_cache
|
||||
|
||||
from calibre.constants import DEBUG, __appname__, get_osx_version, islinux, ismacos
|
||||
from calibre.constants import DEBUG, MAIN_APP_UID, __appname__, get_osx_version, islinux, ismacos, iswindows
|
||||
from calibre.utils.resources import get_image_path as I
|
||||
|
||||
|
||||
@ -177,6 +177,40 @@ class QtNotifier(Notifier):
|
||||
pass
|
||||
|
||||
|
||||
class WinToastNotifier:
|
||||
|
||||
def __init__(self):
|
||||
try:
|
||||
from calibre_extensions.wintoast import initialize_toast
|
||||
except ImportError:
|
||||
self.ok = False
|
||||
else:
|
||||
from qt.core import QApplication
|
||||
app = QApplication.instance()
|
||||
auid = getattr(app, 'windows_app_uid', MAIN_APP_UID)
|
||||
appname = __appname__
|
||||
if app is not None:
|
||||
appname = app.applicationName() or appname
|
||||
try:
|
||||
initialize_toast(appname, auid)
|
||||
except Exception as err:
|
||||
self.ok = False
|
||||
print('Failed to initialize_toast with error:', err, file=sys.stderr)
|
||||
else:
|
||||
self.ok = True
|
||||
|
||||
def __call__(self, body, summary=None, replaces_id=None, timeout=0):
|
||||
if summary:
|
||||
title, message = summary, body
|
||||
else:
|
||||
title, message = '', body
|
||||
from calibre_extensions.wintoast import notify
|
||||
try:
|
||||
notify(title, message, icon())
|
||||
except Exception as err:
|
||||
print('Failed to send toast notification with error:', err, file=sys.stderr)
|
||||
|
||||
|
||||
class DummyNotifier(Notifier):
|
||||
|
||||
ok = True
|
||||
@ -222,6 +256,10 @@ def get_notifier(systray=None):
|
||||
# We dont use Qt's systray based notifier as it uses Growl and is
|
||||
# broken with different versions of Growl
|
||||
ans = DummyNotifier()
|
||||
elif iswindows:
|
||||
ans = WinToastNotifier()
|
||||
if not ans.ok:
|
||||
ans = None
|
||||
if ans is None:
|
||||
ans = QtNotifier(systray)
|
||||
if not ans.ok:
|
||||
@ -234,5 +272,10 @@ def hello():
|
||||
n('hello')
|
||||
|
||||
|
||||
def develop_win():
|
||||
from calibre_extensions.wintoast import initialize_toast, notify
|
||||
initialize_toast(__appname__, MAIN_APP_UID)
|
||||
notify("calibre notification", "hello world", icon())
|
||||
|
||||
if __name__ == '__main__':
|
||||
hello()
|
||||
|
105
src/calibre/utils/windows/wintoast.cpp
Normal file
105
src/calibre/utils/windows/wintoast.cpp
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* wintoast.cpp
|
||||
* Copyright (C) 2024 Kovid Goyal <kovid at kovidgoyal.net>
|
||||
*
|
||||
* Distributed under terms of the GPL3 license.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "wintoastlib.h"
|
||||
using namespace WinToastLib;
|
||||
|
||||
static const char*
|
||||
err_as_atring(WinToast::WinToastError e) {
|
||||
switch(e) {
|
||||
case WinToast::WinToastError::NoError: return "No error";
|
||||
case WinToast::WinToastError::NotInitialized: return "The library has not been initialized";
|
||||
case WinToast::WinToastError::SystemNotSupported: return "The OS does not support WinToast";
|
||||
case WinToast::WinToastError::ShellLinkNotCreated: return "The library was not able to create a Shell Link for the app";
|
||||
case WinToast::WinToastError::InvalidAppUserModelID: return "The AUMI is not a valid one";
|
||||
case WinToast::WinToastError::InvalidParameters: return "Invalid parameters, please double-check the AUMI or App Name";
|
||||
case WinToast::WinToastError::InvalidHandler: return "Invalid handler";
|
||||
case WinToast::WinToastError::NotDisplayed: return "The toast was created correctly but WinToast was not able to display the toast";
|
||||
case WinToast::WinToastError::UnknownError: break;
|
||||
}
|
||||
return "UnknownError";
|
||||
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
set_error(const char *fmt, WinToast::WinToastError error, PyObject *a, PyObject *b) {
|
||||
PyErr_Format(PyExc_OSError, fmt, err_as_atring(error), a, b);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
class WinToastHandler : public WinToastLib::IWinToastHandler {
|
||||
public:
|
||||
WinToastHandler() {}
|
||||
// Public interfaces
|
||||
void toastActivated() const override {}
|
||||
void toastActivated(int actionIndex) const override {
|
||||
wchar_t buf[250];
|
||||
swprintf_s(buf, L"Button clicked: %d", actionIndex);
|
||||
}
|
||||
void toastDismissed(WinToastDismissalReason state) const override {}
|
||||
void toastFailed() const override {}
|
||||
};
|
||||
|
||||
static PyObject*
|
||||
initialize_toast(PyObject *self, PyObject *args) {
|
||||
wchar_raii appname, app_user_model_id;
|
||||
int sp = WinToast::SHORTCUT_POLICY_IGNORE;
|
||||
if (!PyArg_ParseTuple(args, "O&O&|i", py_to_wchar_no_none, &appname, py_to_wchar_no_none, &app_user_model_id, &sp)) return NULL;
|
||||
WinToast::WinToastError error = WinToast::WinToastError::NoError;
|
||||
WinToast::instance()->setAppName(appname.ptr());
|
||||
WinToast::instance()->setAppUserModelId(app_user_model_id.ptr());
|
||||
WinToast::instance()->setShortcutPolicy((WinToast::ShortcutPolicy)sp);
|
||||
if (!WinToast::instance()->initialize(&error)) {
|
||||
return set_error("Failed to initialize WinToast with error: %s using appname: %S and app model id: %S", error, PyTuple_GET_ITEM(args, 0), PyTuple_GET_ITEM(args, 1));
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
notify(PyObject *self, PyObject *args) {
|
||||
wchar_raii title, message, icon_path;
|
||||
if (!PyArg_ParseTuple(args, "O&O&O&", py_to_wchar_no_none, &title, py_to_wchar_no_none, &message, py_to_wchar_no_none, &icon_path)) return NULL;
|
||||
scoped_com_initializer com;
|
||||
if (!com.succeeded()) { PyErr_SetString(PyExc_OSError, "Failed to initialize COM"); return NULL; }
|
||||
WinToastTemplate templ = WinToastTemplate(WinToastTemplate::ImageAndText02);
|
||||
templ.setImagePath(icon_path.ptr(), WinToastTemplate::CropHint::Square);
|
||||
templ.setFirstLine(title.ptr());
|
||||
templ.setSecondLine(message.ptr());
|
||||
templ.setDuration(WinToastTemplate::Duration::Short);
|
||||
WinToast::WinToastError error = WinToast::WinToastError::NoError;
|
||||
INT64 id = WinToast::instance()->showToast(templ, new WinToastHandler(), &error);
|
||||
if (id == -1 || error != WinToast::WinToastError::NoError) {
|
||||
return set_error("Failed to show notification with error: %s using title: %S and message: %S", error, PyTuple_GET_ITEM(args, 0), PyTuple_GET_ITEM(args, 1));
|
||||
}
|
||||
unsigned long long pid = id;
|
||||
return PyLong_FromUnsignedLongLong(pid);
|
||||
}
|
||||
|
||||
static int
|
||||
exec_module(PyObject *m) {
|
||||
if (PyModule_AddIntConstant(m, "SHORTCUT_POLICY_IGNORE", WinToast::SHORTCUT_POLICY_IGNORE) != 0) return -1;
|
||||
if (PyModule_AddIntConstant(m, "SHORTCUT_POLICY_REQUIRE_CREATE", WinToast::SHORTCUT_POLICY_REQUIRE_CREATE) != 0) return -1;
|
||||
if (PyModule_AddIntConstant(m, "SHORTCUT_POLICY_REQUIRE_NO_CREATE", WinToast::SHORTCUT_POLICY_REQUIRE_NO_CREATE) != 0) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyMODINIT_FUNC PyInit_wintoast(void) {
|
||||
#define M(name, args) { #name, name, args, ""}
|
||||
static PyModuleDef_Slot slots[] = { {Py_mod_exec, (void*)exec_module}, {0, NULL} };
|
||||
static struct PyModuleDef module_def = {PyModuleDef_HEAD_INIT};
|
||||
static PyMethodDef methods[] = {
|
||||
M(initialize_toast, METH_VARARGS),
|
||||
M(notify, METH_VARARGS),
|
||||
{0},
|
||||
};
|
||||
module_def.m_name = "wintoast";
|
||||
module_def.m_slots = slots;
|
||||
module_def.m_methods = methods;
|
||||
return PyModuleDef_Init(&module_def);
|
||||
}
|
1362
src/calibre/utils/windows/wintoastlib.cpp
Normal file
1362
src/calibre/utils/windows/wintoastlib.cpp
Normal file
File diff suppressed because it is too large
Load Diff
310
src/calibre/utils/windows/wintoastlib.h
Normal file
310
src/calibre/utils/windows/wintoastlib.h
Normal file
@ -0,0 +1,310 @@
|
||||
/**
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2016-2023 WinToast v1.3.0 - Mohammed Boujemaoui <mohabouje@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef WINTOASTLIB_H
|
||||
#define WINTOASTLIB_H
|
||||
|
||||
#include <Windows.h>
|
||||
#include <sdkddkver.h>
|
||||
#include <WinUser.h>
|
||||
#include <ShObjIdl.h>
|
||||
#include <wrl/implements.h>
|
||||
#include <wrl/event.h>
|
||||
#include <windows.ui.notifications.h>
|
||||
#include <strsafe.h>
|
||||
#include <Psapi.h>
|
||||
#include <ShlObj.h>
|
||||
#include <roapi.h>
|
||||
#include <propvarutil.h>
|
||||
#include <functiondiscoverykeys.h>
|
||||
#include <iostream>
|
||||
#include <winstring.h>
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
using namespace ABI::Windows::Data::Xml::Dom;
|
||||
using namespace ABI::Windows::Foundation;
|
||||
using namespace ABI::Windows::UI::Notifications;
|
||||
using namespace Windows::Foundation;
|
||||
|
||||
namespace WinToastLib {
|
||||
|
||||
class IWinToastHandler {
|
||||
public:
|
||||
enum WinToastDismissalReason {
|
||||
UserCanceled = ToastDismissalReason::ToastDismissalReason_UserCanceled,
|
||||
ApplicationHidden = ToastDismissalReason::ToastDismissalReason_ApplicationHidden,
|
||||
TimedOut = ToastDismissalReason::ToastDismissalReason_TimedOut
|
||||
};
|
||||
|
||||
virtual ~IWinToastHandler() = default;
|
||||
virtual void toastActivated() const = 0;
|
||||
virtual void toastActivated(int actionIndex) const = 0;
|
||||
virtual void toastDismissed(WinToastDismissalReason state) const = 0;
|
||||
virtual void toastFailed() const = 0;
|
||||
};
|
||||
|
||||
class WinToastTemplate {
|
||||
public:
|
||||
enum class Scenario { Default, Alarm, IncomingCall, Reminder };
|
||||
enum Duration { System, Short, Long };
|
||||
enum AudioOption { Default = 0, Silent, Loop };
|
||||
enum TextField { FirstLine = 0, SecondLine, ThirdLine };
|
||||
|
||||
enum WinToastTemplateType {
|
||||
ImageAndText01 = ToastTemplateType::ToastTemplateType_ToastImageAndText01,
|
||||
ImageAndText02 = ToastTemplateType::ToastTemplateType_ToastImageAndText02,
|
||||
ImageAndText03 = ToastTemplateType::ToastTemplateType_ToastImageAndText03,
|
||||
ImageAndText04 = ToastTemplateType::ToastTemplateType_ToastImageAndText04,
|
||||
Text01 = ToastTemplateType::ToastTemplateType_ToastText01,
|
||||
Text02 = ToastTemplateType::ToastTemplateType_ToastText02,
|
||||
Text03 = ToastTemplateType::ToastTemplateType_ToastText03,
|
||||
Text04 = ToastTemplateType::ToastTemplateType_ToastText04
|
||||
};
|
||||
|
||||
enum AudioSystemFile {
|
||||
DefaultSound,
|
||||
IM,
|
||||
Mail,
|
||||
Reminder,
|
||||
SMS,
|
||||
Alarm,
|
||||
Alarm2,
|
||||
Alarm3,
|
||||
Alarm4,
|
||||
Alarm5,
|
||||
Alarm6,
|
||||
Alarm7,
|
||||
Alarm8,
|
||||
Alarm9,
|
||||
Alarm10,
|
||||
Call,
|
||||
Call1,
|
||||
Call2,
|
||||
Call3,
|
||||
Call4,
|
||||
Call5,
|
||||
Call6,
|
||||
Call7,
|
||||
Call8,
|
||||
Call9,
|
||||
Call10,
|
||||
};
|
||||
|
||||
enum CropHint {
|
||||
Square,
|
||||
Circle,
|
||||
};
|
||||
|
||||
WinToastTemplate(_In_ WinToastTemplateType type = WinToastTemplateType::ImageAndText02);
|
||||
~WinToastTemplate();
|
||||
|
||||
void setFirstLine(_In_ std::wstring const& text);
|
||||
void setSecondLine(_In_ std::wstring const& text);
|
||||
void setThirdLine(_In_ std::wstring const& text);
|
||||
void setTextField(_In_ std::wstring const& txt, _In_ TextField pos);
|
||||
void setAttributionText(_In_ std::wstring const& attributionText);
|
||||
void setImagePath(_In_ std::wstring const& imgPath, _In_ CropHint cropHint = CropHint::Square);
|
||||
void setHeroImagePath(_In_ std::wstring const& imgPath, _In_ bool inlineImage = false);
|
||||
void setAudioPath(_In_ WinToastTemplate::AudioSystemFile audio);
|
||||
void setAudioPath(_In_ std::wstring const& audioPath);
|
||||
void setAudioOption(_In_ WinToastTemplate::AudioOption audioOption);
|
||||
void setDuration(_In_ Duration duration);
|
||||
void setExpiration(_In_ INT64 millisecondsFromNow);
|
||||
void setScenario(_In_ Scenario scenario);
|
||||
void addAction(_In_ std::wstring const& label);
|
||||
|
||||
std::size_t textFieldsCount() const;
|
||||
std::size_t actionsCount() const;
|
||||
bool hasImage() const;
|
||||
bool hasHeroImage() const;
|
||||
std::vector<std::wstring> const& textFields() const;
|
||||
std::wstring const& textField(_In_ TextField pos) const;
|
||||
std::wstring const& actionLabel(_In_ std::size_t pos) const;
|
||||
std::wstring const& imagePath() const;
|
||||
std::wstring const& heroImagePath() const;
|
||||
std::wstring const& audioPath() const;
|
||||
std::wstring const& attributionText() const;
|
||||
std::wstring const& scenario() const;
|
||||
INT64 expiration() const;
|
||||
WinToastTemplateType type() const;
|
||||
WinToastTemplate::AudioOption audioOption() const;
|
||||
Duration duration() const;
|
||||
bool isToastGeneric() const;
|
||||
bool isInlineHeroImage() const;
|
||||
bool isCropHintCircle() const;
|
||||
|
||||
private:
|
||||
std::vector<std::wstring> _textFields{};
|
||||
std::vector<std::wstring> _actions{};
|
||||
std::wstring _imagePath{};
|
||||
std::wstring _heroImagePath{};
|
||||
bool _inlineHeroImage{false};
|
||||
std::wstring _audioPath{};
|
||||
std::wstring _attributionText{};
|
||||
std::wstring _scenario{L"Default"};
|
||||
INT64 _expiration{0};
|
||||
AudioOption _audioOption{WinToastTemplate::AudioOption::Default};
|
||||
WinToastTemplateType _type{WinToastTemplateType::Text01};
|
||||
Duration _duration{Duration::System};
|
||||
CropHint _cropHint{CropHint::Square};
|
||||
};
|
||||
|
||||
class WinToast {
|
||||
public:
|
||||
enum WinToastError {
|
||||
NoError = 0,
|
||||
NotInitialized,
|
||||
SystemNotSupported,
|
||||
ShellLinkNotCreated,
|
||||
InvalidAppUserModelID,
|
||||
InvalidParameters,
|
||||
InvalidHandler,
|
||||
NotDisplayed,
|
||||
UnknownError
|
||||
};
|
||||
|
||||
enum ShortcutResult {
|
||||
SHORTCUT_UNCHANGED = 0,
|
||||
SHORTCUT_WAS_CHANGED = 1,
|
||||
SHORTCUT_WAS_CREATED = 2,
|
||||
|
||||
SHORTCUT_MISSING_PARAMETERS = -1,
|
||||
SHORTCUT_INCOMPATIBLE_OS = -2,
|
||||
SHORTCUT_COM_INIT_FAILURE = -3,
|
||||
SHORTCUT_CREATE_FAILED = -4
|
||||
};
|
||||
|
||||
enum ShortcutPolicy {
|
||||
/* Don't check, create, or modify a shortcut. */
|
||||
SHORTCUT_POLICY_IGNORE = 0,
|
||||
/* Require a shortcut with matching AUMI, don't create or modify an existing one. */
|
||||
SHORTCUT_POLICY_REQUIRE_NO_CREATE = 1,
|
||||
/* Require a shortcut with matching AUMI, create if missing, modify if not matching. This is the default. */
|
||||
SHORTCUT_POLICY_REQUIRE_CREATE = 2,
|
||||
};
|
||||
|
||||
WinToast(void);
|
||||
virtual ~WinToast();
|
||||
static WinToast* instance();
|
||||
static bool isCompatible();
|
||||
static bool isSupportingModernFeatures();
|
||||
static bool isWin10AnniversaryOrHigher();
|
||||
static std::wstring configureAUMI(_In_ std::wstring const& companyName, _In_ std::wstring const& productName,
|
||||
_In_ std::wstring const& subProduct = std::wstring(),
|
||||
_In_ std::wstring const& versionInformation = std::wstring());
|
||||
static std::wstring const& strerror(_In_ WinToastError error);
|
||||
virtual bool initialize(_Out_opt_ WinToastError* error = nullptr);
|
||||
virtual bool isInitialized() const;
|
||||
virtual bool hideToast(_In_ INT64 id);
|
||||
virtual INT64 showToast(_In_ WinToastTemplate const& toast, _In_ IWinToastHandler* eventHandler,
|
||||
_Out_opt_ WinToastError* error = nullptr);
|
||||
virtual void clear();
|
||||
virtual enum ShortcutResult createShortcut();
|
||||
|
||||
std::wstring const& appName() const;
|
||||
std::wstring const& appUserModelId() const;
|
||||
void setAppUserModelId(_In_ std::wstring const& aumi);
|
||||
void setAppName(_In_ std::wstring const& appName);
|
||||
void setShortcutPolicy(_In_ ShortcutPolicy policy);
|
||||
|
||||
protected:
|
||||
struct NotifyData {
|
||||
NotifyData(){};
|
||||
NotifyData(_In_ ComPtr<IToastNotification> notify, _In_ EventRegistrationToken activatedToken,
|
||||
_In_ EventRegistrationToken dismissedToken, _In_ EventRegistrationToken failedToken) :
|
||||
_notify(notify), _activatedToken(activatedToken), _dismissedToken(dismissedToken), _failedToken(failedToken) {}
|
||||
|
||||
~NotifyData() {
|
||||
RemoveTokens();
|
||||
}
|
||||
|
||||
void RemoveTokens() {
|
||||
if (!_readyForDeletion) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_previouslyTokenRemoved) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_notify.Get()) {
|
||||
return;
|
||||
}
|
||||
|
||||
_notify->remove_Activated(_activatedToken);
|
||||
_notify->remove_Dismissed(_dismissedToken);
|
||||
_notify->remove_Failed(_failedToken);
|
||||
_previouslyTokenRemoved = true;
|
||||
}
|
||||
|
||||
void markAsReadyForDeletion() {
|
||||
_readyForDeletion = true;
|
||||
}
|
||||
|
||||
bool isReadyForDeletion() const {
|
||||
return _readyForDeletion;
|
||||
}
|
||||
|
||||
IToastNotification* notification() {
|
||||
return _notify.Get();
|
||||
}
|
||||
|
||||
private:
|
||||
ComPtr<IToastNotification> _notify{nullptr};
|
||||
EventRegistrationToken _activatedToken{};
|
||||
EventRegistrationToken _dismissedToken{};
|
||||
EventRegistrationToken _failedToken{};
|
||||
bool _readyForDeletion{false};
|
||||
bool _previouslyTokenRemoved{false};
|
||||
};
|
||||
|
||||
bool _isInitialized{false};
|
||||
bool _hasCoInitialized{false};
|
||||
ShortcutPolicy _shortcutPolicy{SHORTCUT_POLICY_REQUIRE_CREATE};
|
||||
std::wstring _appName{};
|
||||
std::wstring _aumi{};
|
||||
std::map<INT64, NotifyData> _buffer{};
|
||||
|
||||
void markAsReadyForDeletion(_In_ INT64 id);
|
||||
HRESULT validateShellLinkHelper(_Out_ bool& wasChanged);
|
||||
HRESULT createShellLinkHelper();
|
||||
HRESULT setImageFieldHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& path, _In_ bool isToastGeneric, bool isCropHintCircle);
|
||||
HRESULT setHeroImageHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& path, _In_ bool isInlineImage);
|
||||
HRESULT setBindToastGenericHelper(_In_ IXmlDocument* xml);
|
||||
HRESULT
|
||||
setAudioFieldHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& path,
|
||||
_In_opt_ WinToastTemplate::AudioOption option = WinToastTemplate::AudioOption::Default);
|
||||
HRESULT setTextFieldHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& text, _In_ UINT32 pos);
|
||||
HRESULT setAttributionTextFieldHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& text);
|
||||
HRESULT addActionHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& action, _In_ std::wstring const& arguments);
|
||||
HRESULT addDurationHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& duration);
|
||||
HRESULT addScenarioHelper(_In_ IXmlDocument* xml, _In_ std::wstring const& scenario);
|
||||
ComPtr<IToastNotifier> notifier(_In_ bool* succeded) const;
|
||||
void setError(_Out_opt_ WinToastError* error, _In_ WinToastError value);
|
||||
};
|
||||
} // namespace WinToastLib
|
||||
#endif // WINTOASTLIB_H
|
Loading…
x
Reference in New Issue
Block a user