├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── _config.yml ├── python.ico ├── requirements.txt ├── setup.cfg ├── setup.py ├── test └── test.py └── win10toast ├── __init__.py ├── __main__.py └── data └── python.ico /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | lib/ 17 | lib64/ 18 | parts/ 19 | sdist/ 20 | var/ 21 | *.egg-info/ 22 | .installed.cfg 23 | *.egg 24 | 25 | # PyInstaller 26 | # Usually these files are written by a python script from a template 27 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 28 | *.manifest 29 | *.spec 30 | 31 | # Installer logs 32 | pip-log.txt 33 | pip-delete-this-directory.txt 34 | 35 | # Unit test / coverage reports 36 | htmlcov/ 37 | .tox/ 38 | .coverage 39 | .cache 40 | nosetests.xml 41 | coverage.xml 42 | 43 | # Translations 44 | *.mo 45 | *.pot 46 | 47 | # Django stuff: 48 | *.log 49 | 50 | # Sphinx documentation 51 | docs/_build/ 52 | 53 | # PyBuilder 54 | target/ 55 | 56 | # ========================= 57 | # Operating System Files 58 | # ========================= 59 | 60 | # OSX 61 | # ========================= 62 | 63 | .DS_Store 64 | .AppleDouble 65 | .LSOverride 66 | 67 | # Thumbnails 68 | ._* 69 | 70 | # Files that might appear on external disk 71 | .Spotlight-V100 72 | .Trashes 73 | 74 | # Directories potentially created on remote AFP share 75 | .AppleDB 76 | .AppleDesktop 77 | Network Trash Folder 78 | Temporary Items 79 | .apdisk 80 | 81 | # Windows 82 | # ========================= 83 | 84 | # Windows image file caches 85 | Thumbs.db 86 | ehthumbs.db 87 | 88 | # Folder config file 89 | Desktop.ini 90 | 91 | # Recycle Bin used on file shares 92 | $RECYCLE.BIN/ 93 | 94 | # Windows Installer files 95 | *.cab 96 | *.msi 97 | *.msm 98 | *.msp 99 | 100 | # Windows shortcuts 101 | *.lnk 102 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Jithu R Jacob 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Windows 10 Toast Notifications 2 | [![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg)](https://www.python.org/) [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fjithurjacob%2FWindows-10-Toast-Notifications.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fjithurjacob%2FWindows-10-Toast-Notifications?ref=badge_shield) [![HitCount](http://hits.dwyl.io/jithurjacob/Windows-10-Toast-Notifications.svg)](http://hits.dwyl.io/jithurjacob/Windows-10-Toast-Notifications) [![MIT license](https://img.shields.io/badge/License-MIT-blue.svg)](https://lbesson.mit-license.org/) 3 | 4 | An easy-to-use Python library for displaying Windows 10 Toast Notifications which is useful for Windows GUI development. 5 | 6 | 7 | ![o7ja4 1](https://cloud.githubusercontent.com/assets/7101452/19763806/75f71ba4-9c5d-11e6-9f16-d0d4bf43e63e.png) 8 | 9 | 10 | ## Installation 11 | 12 | ``` 13 | pip install win10toast 14 | ``` 15 | 16 | ## Requirements 17 | 18 | ### Installation of pywin32 19 | ``` 20 | pypiwin32 21 | setuptools 22 | ``` 23 | 24 | ## Example 25 | 26 | ``` 27 | from win10toast import ToastNotifier 28 | toaster = ToastNotifier() 29 | toaster.show_toast("Hello World!!!", 30 | "Python is 10 seconds awsm!", 31 | icon_path="custom.ico", 32 | duration=10) 33 | 34 | toaster.show_toast("Example two", 35 | "This notification is in it's own thread!", 36 | icon_path=None, 37 | duration=5, 38 | threaded=True) 39 | # Wait for threaded notification to finish 40 | while toaster.notification_active(): time.sleep(0.1) 41 | ``` 42 | 43 | ## Contributors [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/jithurjacob/Windows-10-Toast-Notifications/issues) 44 | 45 | + [sidc9](https://github.com/sidc9) 46 | + [sakurai-youhei](https://github.com/sakurai-youhei) 47 | + [BroderickCarlin](https://github.com/BroderickCarlin) 48 | + [florianluediger](https://github.com/florianluediger) 49 | + [eric-wieser](https://github.com/eric-wieser) 50 | + [Guts](https://github.com/Guts) 51 | 52 | 53 | ## License 54 | [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fjithurjacob%2FWindows-10-Toast-Notifications.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fjithurjacob%2FWindows-10-Toast-Notifications?ref=badge_large) 55 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /python.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jithurjacob/Windows-10-Toast-Notifications/9d52b73f1af6c60162cf09b99269c4f7b13cdb00/python.ico -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pypiwin32 2 | setuptools -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | description-file = README.md 3 | [bdist_wheel] 4 | universal=1 -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | 2 | from operator import attrgetter 3 | from os import path 4 | 5 | from pip.req import parse_requirements 6 | from setuptools import setup 7 | 8 | def read(fname): 9 | return open(path.join(path.dirname(__file__), fname)).read() 10 | 11 | 12 | def from_here(relative_path): 13 | return path.join(path.dirname(__file__), relative_path) 14 | 15 | 16 | requirements_txt = list(map(str, map( 17 | attrgetter("req"), 18 | parse_requirements(from_here("requirements.txt"), session="") 19 | ))) 20 | 21 | setup( 22 | name="win10toast", 23 | version="0.9", 24 | install_requires=requirements_txt, 25 | packages=["win10toast"], 26 | license="BSD", 27 | url="https://github.com/jithurjacob/Windows-10-Toast-Notifications", 28 | download_url = 'https://github.com/jithurjacob/Windows-10-Toast-Notifications/tarball/0.9', 29 | description=( 30 | "An easy-to-use Python library for displaying " 31 | "Windows 10 Toast Notifications" 32 | ), 33 | include_package_data=True, 34 | package_data={ 35 | '': ['*.txt'], 36 | 'win10toast': ['data/*.ico'], 37 | }, 38 | long_description=read('README.md'), 39 | author="Jithu R Jacob", 40 | author_email="jithurjacob@gmail.com", 41 | classifiers=[ 42 | "Development Status :: 3 - Alpha", 43 | "Topic :: Utilities", 44 | 'Operating System :: Microsoft', 45 | 'Environment :: Win32 (MS Windows)', 46 | "License :: OSI Approved :: MIT License", 47 | ], 48 | ) 49 | -------------------------------------------------------------------------------- /test/test.py: -------------------------------------------------------------------------------- 1 | from win10toast import ToastNotifier 2 | 3 | if __name__ == "__main__": 4 | # Example 5 | toaster = ToastNotifier() 6 | toaster.show_toast( 7 | "Hello World!!!", 8 | "Python is 10 seconds awsm!", 9 | duration=10) 10 | toaster.show_toast( 11 | "Example two", 12 | "Once you start coding in Python you'll hate other languages") 13 | -------------------------------------------------------------------------------- /win10toast/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | from __future__ import print_function 3 | from __future__ import unicode_literals 4 | 5 | __all__ = ['ToastNotifier'] 6 | 7 | # ############################################################################# 8 | # ########## Libraries ############# 9 | # ################################## 10 | # standard library 11 | import logging 12 | import threading 13 | from os import path 14 | from time import sleep 15 | from pkg_resources import Requirement 16 | from pkg_resources import resource_filename 17 | 18 | # 3rd party modules 19 | from win32api import GetModuleHandle 20 | from win32api import PostQuitMessage 21 | from win32con import CW_USEDEFAULT 22 | from win32con import IDI_APPLICATION 23 | from win32con import IMAGE_ICON 24 | from win32con import LR_DEFAULTSIZE 25 | from win32con import LR_LOADFROMFILE 26 | from win32con import WM_DESTROY 27 | from win32con import WM_USER 28 | from win32con import WS_OVERLAPPED 29 | from win32con import WS_SYSMENU 30 | from win32gui import CreateWindow 31 | from win32gui import DestroyWindow 32 | from win32gui import LoadIcon 33 | from win32gui import LoadImage 34 | from win32gui import NIF_ICON 35 | from win32gui import NIF_INFO 36 | from win32gui import NIF_MESSAGE 37 | from win32gui import NIF_TIP 38 | from win32gui import NIM_ADD 39 | from win32gui import NIM_DELETE 40 | from win32gui import NIM_MODIFY 41 | from win32gui import RegisterClass 42 | from win32gui import UnregisterClass 43 | from win32gui import Shell_NotifyIcon 44 | from win32gui import UpdateWindow 45 | from win32gui import WNDCLASS 46 | 47 | # ############################################################################ 48 | # ########### Classes ############## 49 | # ################################## 50 | 51 | 52 | class ToastNotifier(object): 53 | """Create a Windows 10 toast notification. 54 | 55 | from: https://github.com/jithurjacob/Windows-10-Toast-Notifications 56 | """ 57 | 58 | def __init__(self): 59 | """Initialize.""" 60 | self._thread = None 61 | 62 | def _show_toast(self, title, msg, 63 | icon_path, duration): 64 | """Notification settings. 65 | 66 | :title: notification title 67 | :msg: notification message 68 | :icon_path: path to the .ico file to custom notification 69 | :duration: delay in seconds before notification self-destruction 70 | """ 71 | message_map = {WM_DESTROY: self.on_destroy, } 72 | 73 | # Register the window class. 74 | self.wc = WNDCLASS() 75 | self.hinst = self.wc.hInstance = GetModuleHandle(None) 76 | self.wc.lpszClassName = str("PythonTaskbar") # must be a string 77 | self.wc.lpfnWndProc = message_map # could also specify a wndproc. 78 | try: 79 | self.classAtom = RegisterClass(self.wc) 80 | except: 81 | pass #not sure of this 82 | style = WS_OVERLAPPED | WS_SYSMENU 83 | self.hwnd = CreateWindow(self.classAtom, "Taskbar", style, 84 | 0, 0, CW_USEDEFAULT, 85 | CW_USEDEFAULT, 86 | 0, 0, self.hinst, None) 87 | UpdateWindow(self.hwnd) 88 | 89 | # icon 90 | if icon_path is not None: 91 | icon_path = path.realpath(icon_path) 92 | else: 93 | icon_path = resource_filename(Requirement.parse("win10toast"), "win10toast/data/python.ico") 94 | icon_flags = LR_LOADFROMFILE | LR_DEFAULTSIZE 95 | try: 96 | hicon = LoadImage(self.hinst, icon_path, 97 | IMAGE_ICON, 0, 0, icon_flags) 98 | except Exception as e: 99 | logging.error("Some trouble with the icon ({}): {}" 100 | .format(icon_path, e)) 101 | hicon = LoadIcon(0, IDI_APPLICATION) 102 | 103 | # Taskbar icon 104 | flags = NIF_ICON | NIF_MESSAGE | NIF_TIP 105 | nid = (self.hwnd, 0, flags, WM_USER + 20, hicon, "Tooltip") 106 | Shell_NotifyIcon(NIM_ADD, nid) 107 | Shell_NotifyIcon(NIM_MODIFY, (self.hwnd, 0, NIF_INFO, 108 | WM_USER + 20, 109 | hicon, "Balloon Tooltip", msg, 200, 110 | title)) 111 | # take a rest then destroy 112 | sleep(duration) 113 | DestroyWindow(self.hwnd) 114 | UnregisterClass(self.wc.lpszClassName, None) 115 | return None 116 | 117 | def show_toast(self, title="Notification", msg="Here comes the message", 118 | icon_path=None, duration=5, threaded=False): 119 | """Notification settings. 120 | 121 | :title: notification title 122 | :msg: notification message 123 | :icon_path: path to the .ico file to custom notification 124 | :duration: delay in seconds before notification self-destruction 125 | """ 126 | if not threaded: 127 | self._show_toast(title, msg, icon_path, duration) 128 | else: 129 | if self.notification_active(): 130 | # We have an active notification, let is finish so we don't spam them 131 | return False 132 | 133 | self._thread = threading.Thread(target=self._show_toast, args=(title, msg, icon_path, duration)) 134 | self._thread.start() 135 | return True 136 | 137 | def notification_active(self): 138 | """See if we have an active notification showing""" 139 | if self._thread != None and self._thread.is_alive(): 140 | # We have an active notification, let is finish we don't spam them 141 | return True 142 | return False 143 | 144 | def on_destroy(self, hwnd, msg, wparam, lparam): 145 | """Clean after notification ended. 146 | 147 | :hwnd: 148 | :msg: 149 | :wparam: 150 | :lparam: 151 | """ 152 | nid = (self.hwnd, 0) 153 | Shell_NotifyIcon(NIM_DELETE, nid) 154 | PostQuitMessage(0) 155 | 156 | return None 157 | 158 | -------------------------------------------------------------------------------- /win10toast/__main__.py: -------------------------------------------------------------------------------- 1 | from win10toast import ToastNotifier 2 | import time 3 | 4 | # ############################################################################# 5 | # ###### Stand alone program ######## 6 | # ################################### 7 | if __name__ == "__main__": 8 | # Example 9 | toaster = ToastNotifier() 10 | toaster.show_toast( 11 | "Hello World!!!", 12 | "Python is 10 seconds awsm!", 13 | duration=10) 14 | toaster.show_toast( 15 | "Example two", 16 | "This notification is in it's own thread!", 17 | icon_path=None, 18 | duration=5, 19 | threaded=True 20 | ) 21 | # Wait for threaded notification to finish 22 | while toaster.notification_active(): time.sleep(0.1) 23 | -------------------------------------------------------------------------------- /win10toast/data/python.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jithurjacob/Windows-10-Toast-Notifications/9d52b73f1af6c60162cf09b99269c4f7b13cdb00/win10toast/data/python.ico --------------------------------------------------------------------------------