├── .gitattributes ├── .gitignore ├── .idea ├── misc.xml ├── modules.xml ├── vcs.xml ├── workspace.xml └── zroya.iml ├── LICENSE.txt ├── MANIFEST.in ├── README.md ├── TODO ├── changelog ├── docs ├── .buildinfo ├── .nojekyll ├── _images │ ├── example_full_features_action.png │ ├── example_full_features_attribution.png │ ├── in_action_multiline_image.png │ ├── in_action_one_line.png │ ├── tutorials_callbacks_final.gif │ ├── tutorials_first_steps.png │ ├── tutorials_first_steps_troubleshooting.gif │ ├── tutorials_template_actions.png │ ├── tutorials_template_image.png │ └── tutorials_template_three_lines.png ├── _sources │ ├── commiting.rst.txt │ ├── committing.rst.txt │ ├── content.rst.txt │ ├── documentation.rst.txt │ ├── in_action.rst.txt │ ├── index.rst.txt │ └── tutorials │ │ ├── callbacks.rst.txt │ │ ├── index.rst.txt │ │ ├── installation.rst.txt │ │ └── template.rst.txt ├── _static │ ├── ajax-loader.gif │ ├── alabaster.css │ ├── audio.html │ ├── audio │ │ ├── Alarm01.wav │ │ ├── Alarm02.wav │ │ ├── Alarm03.wav │ │ ├── Alarm04.wav │ │ ├── Alarm05.wav │ │ ├── Alarm06.wav │ │ ├── Alarm07.wav │ │ ├── Alarm08.wav │ │ ├── Alarm09.wav │ │ ├── Alarm10.wav │ │ ├── Default.wav │ │ ├── Email.wav │ │ ├── IM.wav │ │ ├── Reminder.wav │ │ ├── Ring01.wav │ │ ├── Ring02.wav │ │ ├── Ring03.wav │ │ ├── Ring04.wav │ │ ├── Ring05.wav │ │ ├── Ring06.wav │ │ ├── Ring07.wav │ │ ├── Ring08.wav │ │ ├── Ring09.wav │ │ └── Ring10.wav │ ├── basic.css │ ├── comment-bright.png │ ├── comment-close.png │ ├── comment.png │ ├── css │ │ └── styles.css │ ├── custom.css │ ├── desktop.ini │ ├── doctools.js │ ├── documentation_options.js │ ├── down-pressed.png │ ├── down.png │ ├── example_full_features.png │ ├── example_full_features_action.png │ ├── example_full_features_attribution.png │ ├── file.png │ ├── in_action_multiline_image.png │ ├── in_action_one_line.png │ ├── jquery-3.2.1.js │ ├── jquery.js │ ├── minus.png │ ├── plus.png │ ├── pygments.css │ ├── searchtools.js │ ├── tutorials_callbacks_final.gif │ ├── tutorials_first_steps.png │ ├── tutorials_first_steps_troubleshooting.gif │ ├── tutorials_template_actions.png │ ├── tutorials_template_image.png │ ├── tutorials_template_three_lines.png │ ├── underscore-1.3.1.js │ ├── underscore.js │ ├── up-pressed.png │ ├── up.png │ └── websupport.js ├── commiting.html ├── committing.html ├── content.html ├── documentation.html ├── genindex.html ├── in_action.html ├── index.html ├── objects.inv ├── py-modindex.html ├── search.html ├── searchindex.js └── tutorials │ ├── callbacks.html │ ├── index.html │ ├── installation.html │ └── template.html ├── docs_source ├── doxygen │ └── Doxyfile └── sphinx │ ├── make.bat │ └── source │ ├── _static │ ├── audio.html │ ├── audio │ │ ├── Alarm01.wav │ │ ├── Alarm02.wav │ │ ├── Alarm03.wav │ │ ├── Alarm04.wav │ │ ├── Alarm05.wav │ │ ├── Alarm06.wav │ │ ├── Alarm07.wav │ │ ├── Alarm08.wav │ │ ├── Alarm09.wav │ │ ├── Alarm10.wav │ │ ├── Default.wav │ │ ├── Email.wav │ │ ├── IM.wav │ │ ├── Reminder.wav │ │ ├── Ring01.wav │ │ ├── Ring02.wav │ │ ├── Ring03.wav │ │ ├── Ring04.wav │ │ ├── Ring05.wav │ │ ├── Ring06.wav │ │ ├── Ring07.wav │ │ ├── Ring08.wav │ │ ├── Ring09.wav │ │ └── Ring10.wav │ ├── css │ │ └── styles.css │ ├── desktop.ini │ ├── example_full_features.png │ ├── example_full_features_action.png │ ├── example_full_features_attribution.png │ ├── in_action_multiline_image.png │ ├── in_action_one_line.png │ ├── tutorials_callbacks_final.gif │ ├── tutorials_first_steps.png │ ├── tutorials_first_steps_troubleshooting.gif │ ├── tutorials_template_actions.png │ ├── tutorials_template_image.png │ └── tutorials_template_three_lines.png │ ├── committing.rst │ ├── conf.py │ ├── content.rst │ ├── documentation.rst │ ├── in_action.rst │ ├── index.rst │ └── tutorials │ ├── callbacks.rst │ ├── index.rst │ ├── installation.rst │ └── template.rst ├── generate_stubs.py ├── module ├── event_handler.cpp ├── event_handler.h ├── init.cpp ├── init.h ├── module.sln ├── module │ ├── module.vcxproj │ ├── module.vcxproj.filters │ └── module.vcxproj.user ├── py_init.cpp ├── py_init.h ├── py_module.cpp ├── py_module.h ├── py_template.cpp ├── py_template.h ├── py_utils.cpp ├── py_utils.h ├── utils.cpp ├── utils.h ├── wintoastlib.cpp └── wintoastlib.h ├── setup.py ├── tests ├── files │ ├── Readme.txt │ └── image.png ├── test_actions.py ├── test_callbacks.py ├── test_hide.py ├── test_init.py ├── test_show.py └── test_template.py └── zroya ├── __init__.py ├── dismiss_reason.py ├── template_enums.py ├── version.py └── zroya.pyi /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | .vs 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | local_settings.py 56 | 57 | # Flask stuff: 58 | instance/ 59 | .webassets-cache 60 | 61 | # Scrapy stuff: 62 | .scrapy 63 | 64 | # Sphinx documentation 65 | docs/_build/ 66 | 67 | # PyBuilder 68 | target/ 69 | 70 | # Jupyter Notebook 71 | .ipynb_checkpoints 72 | 73 | # pyenv 74 | .python-version 75 | 76 | # celery beat schedule file 77 | celerybeat-schedule 78 | 79 | # SageMath parsed files 80 | *.sage.py 81 | 82 | # Environments 83 | .env 84 | .venv 85 | env/ 86 | venv/ 87 | ENV/ 88 | 89 | # Spyder project settings 90 | .spyderproject 91 | .spyproject 92 | 93 | # Rope project settings 94 | .ropeproject 95 | 96 | # mkdocs documentation 97 | /site 98 | 99 | # mypy 100 | .mypy_cache/ 101 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/zroya.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 11 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Jan Malčák 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. -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include generate_stubs.py 2 | include README.md 3 | include ./module/*.h 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) 2 | [![PyPI version](https://badge.fury.io/py/zroya.svg)](https://pypi.python.org/pypi/zroya/) 3 | [![PyPI status](https://img.shields.io/pypi/status/zroya.svg)](https://pypi.python.org/pypi/zroya/) 4 | [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://gitHub.com/malja/zroya/graphs/commit-activity) 5 | 6 | # zroya2 7 | Zroya is a Python package for creating native Windows notifications. 8 | 9 | In contrast to first version of zroya, zroya2 is a Python extension built around C++ 10 | [WinToast](https://github.com/mohabouje/WinToast) library. 11 | 12 | **Note**: Zroya2 is in beta testing. I would be grateful for any bug reports. 13 | 14 | ## Prerequisites 15 | 16 | There are no requirements at the moment. 17 | 18 | ## Installation 19 | 20 | Zroya2 is now available from pypi: 21 | 22 | ``` 23 | python -m pip install zroya 24 | ``` 25 | 26 | ## Example 27 | 28 | ```python 29 | 30 | import zroya 31 | 32 | # Initialize zroya module. Make sure to call this function. 33 | # All parameters are required 34 | zroya.init("YourAppName", "CompanyName", "ProductName", "SubProduct", "Version") 35 | 36 | # Create notification template. TYPE_TEXT1 means one bold line withou image. 37 | template = zroya.Template( zroya.TemplateType.Text1 ) 38 | # Set first line 39 | template.setFirstLine("My First line") 40 | 41 | # Save notification id for later use 42 | notificationID = zroya.show(template) 43 | 44 | # .. do something, maybe sleep? 45 | 46 | # Hide notification 47 | zroya.hide(notificationID) 48 | ``` 49 | 50 | ## Documentation 51 | 52 | You may find some limited documentation on [Zroya Page](https://malja.github.io/zroya) 53 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | Required before release: 2 | ======================== 3 | 4 | - Write documentation for C part of the project 5 | - Add more tests 6 | - Add Template __init__ method to zroya.pyi 7 | 8 | Future goals: 9 | ============== 10 | 11 | - Make sure it is not required to call init function 12 | - Add support for future WinToast features 13 | - Commit changes in WinToast library back to its github project 14 | - Add removeAction, getAction methods to WinToastLib -------------------------------------------------------------------------------- /changelog: -------------------------------------------------------------------------------- 1 | 0.1.0 2 | ----- 3 | 4 | - Basic functionality 5 | 6 | 0.1.1 7 | ----- 8 | 9 | - Sound is now mutable 10 | - Better documentation 11 | 12 | 0.1.2 13 | ----- 14 | 15 | - Notifications may be hidden from source 16 | - Timeouts - after certain time notification disappears 17 | - on_timeout now triggers after defined timeout expires and notification is removed 18 | - on_hide now triggers after notification is hidden from code 19 | 20 | 0.2.0 21 | ----- 22 | 23 | - New C based module for python with native Windows notification support 24 | - Does not support events yet. 25 | 26 | 04.04.2018 27 | - Script generage_stubs.py is called automatically after build_ext command 28 | - First version of Doxygen documentation 29 | - Changes in WinToastLib namespaces 30 | 31 | 11.04.2018 32 | - New Python class DismissReason 33 | - Working callbacks 34 | - Visual Studio project for C/C++ code 35 | - Use get/set methods instead of multipurpose methods in zroya.Template 36 | 37 | 19. 04. 2018 38 | - Everything seems to work properly 39 | - New documentation for python code available from https://malja.github.io/zroya 40 | 41 | 26. 04. 2018 42 | - Added In Action page to documentation 43 | - Added Committing to zroya page to documentation 44 | - Added version and release variables to zroya.py, which are used in sphinx config and setup.py 45 | - New upload, docs, test, stubs commands in setup.py 46 | - Some changes in stub generating. 47 | - Changed tests for zroya.Template.set*Line to handle TypeError instead ValueError 48 | - Changed tests for zroya.Template.get/setImage to work with absolute paths 49 | - Removed sphinx makefile, since make.bat is much better option which doesn't require make to be installed 50 | - Removed C documentation. It is not ready for production yet. 51 | 52 | 0.2.1 53 | ----- 54 | 55 | - Tried to fix https://github.com/malja/zroya/issues/11 56 | - Removed /utf-8 parameter from setup.py 57 | 58 | 0.2.2 59 | ----- 60 | 61 | - Tried to fix https://github.com/malja/zroya/issues/11 62 | - Changed setup.py to include all files under /zroya directory 63 | -------------------------------------------------------------------------------- /docs/.buildinfo: -------------------------------------------------------------------------------- 1 | # Sphinx build info version 1 2 | # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. 3 | config: be625054012c59005cd92cdf8ec350c8 4 | tags: 645f666f9bcd5a90fca523b33c5a78b7 5 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/.nojekyll -------------------------------------------------------------------------------- /docs/_images/example_full_features_action.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_images/example_full_features_action.png -------------------------------------------------------------------------------- /docs/_images/example_full_features_attribution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_images/example_full_features_attribution.png -------------------------------------------------------------------------------- /docs/_images/in_action_multiline_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_images/in_action_multiline_image.png -------------------------------------------------------------------------------- /docs/_images/in_action_one_line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_images/in_action_one_line.png -------------------------------------------------------------------------------- /docs/_images/tutorials_callbacks_final.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_images/tutorials_callbacks_final.gif -------------------------------------------------------------------------------- /docs/_images/tutorials_first_steps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_images/tutorials_first_steps.png -------------------------------------------------------------------------------- /docs/_images/tutorials_first_steps_troubleshooting.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_images/tutorials_first_steps_troubleshooting.gif -------------------------------------------------------------------------------- /docs/_images/tutorials_template_actions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_images/tutorials_template_actions.png -------------------------------------------------------------------------------- /docs/_images/tutorials_template_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_images/tutorials_template_image.png -------------------------------------------------------------------------------- /docs/_images/tutorials_template_three_lines.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_images/tutorials_template_three_lines.png -------------------------------------------------------------------------------- /docs/_sources/commiting.rst.txt: -------------------------------------------------------------------------------- 1 | Committing to zroya 2 | =================== 3 | 4 | Changes in C files 5 | ------------------ 6 | 7 | 1) Build Python extension from C source 8 | 9 | > python setup.py build 10 | 11 | Make sure there are no errors. 12 | 13 | 2) Test it with existing tests 14 | 15 | > python setup.py test 16 | 17 | Make sure all tests passed 18 | 19 | 3) Write your own tests when necessary. 20 | 21 | 4) Change documentation. See Changes in Documentation 22 | 23 | 5) Make stubs 24 | 25 | > python setup.py stubs 26 | 27 | Changes in Python files 28 | ----------------------- 29 | 30 | 1) Test your changes with existing tests 31 | 32 | > python setup.py test 33 | 34 | 2) Write your own tests when necessary. 35 | 36 | 3) Change documentation. See Changes in Documentation 37 | 38 | 4) Make stubs 39 | 40 | > python setup.py stubs 41 | 42 | Changes in documentation 43 | ------------------------ 44 | 45 | 1) Build html documentation 46 | 47 | > python setup.py docs 48 | -------------------------------------------------------------------------------- /docs/_sources/committing.rst.txt: -------------------------------------------------------------------------------- 1 | Committing to zroya 2 | =================== 3 | 4 | This page is work in progress. 5 | 6 | Changes in C files 7 | ------------------ 8 | 9 | 1. Build Python extension from C source. 10 | 11 | .. code-block:: bash 12 | 13 | python setup.py build 14 | 15 | Make sure there are no errors. 16 | 17 | 2. Run current tests. 18 | 19 | .. code-block:: bash 20 | 21 | python setup.py test 22 | 23 | 3. Write your own tests when necessary. 24 | 25 | 4. Change documentation. See :ref:`changes_in_documentation` section. 26 | 27 | 5. Make stubs 28 | 29 | .. code-block:: bash 30 | 31 | python setup.py stubs 32 | 33 | Changes in Python files 34 | ----------------------- 35 | 36 | 1. Test your changes with existing tests 37 | 38 | .. code-block:: bash 39 | 40 | python setup.py test 41 | 42 | 2. Write your own tests when necessary. 43 | 44 | 3. Change documentation. See :ref:`changes_in_documentation` section. 45 | 46 | 4. Make stubs 47 | 48 | .. code-block:: bash 49 | 50 | python setup.py stubs 51 | 52 | .. _changes_in_documentation: 53 | 54 | Changes in documentation 55 | ------------------------ 56 | 57 | 1. Build html documentation. 58 | 59 | .. code-block:: bash 60 | 61 | python setup.py docs 62 | -------------------------------------------------------------------------------- /docs/_sources/content.rst.txt: -------------------------------------------------------------------------------- 1 | Tutorial 2 | ======== 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | 7 | in_action 8 | tutorials/installation 9 | tutorials/index 10 | tutorials/template 11 | tutorials/callbacks 12 | documentation 13 | committing 14 | -------------------------------------------------------------------------------- /docs/_sources/documentation.rst.txt: -------------------------------------------------------------------------------- 1 | API Documentation 2 | ================= 3 | 4 | Functions 5 | --------- 6 | .. automodule:: zroya 7 | :members: init, show, hide 8 | 9 | Template 10 | -------- 11 | 12 | .. autoclass:: zroya.Template 13 | :members: 14 | 15 | TemplateType 16 | ^^^^^^^^^^^^ 17 | 18 | .. autoclass:: zroya.TemplateType 19 | :members: 20 | 21 | Audio 22 | ----- 23 | 24 | .. autoclass:: zroya.Audio 25 | :members: 26 | 27 | AudioMode 28 | ^^^^^^^^^ 29 | 30 | .. autoclass:: zroya.AudioMode 31 | :members: 32 | 33 | DismissReason 34 | ------------- 35 | 36 | .. autoclass:: zroya.DismissReason 37 | :members: 38 | -------------------------------------------------------------------------------- /docs/_sources/in_action.rst.txt: -------------------------------------------------------------------------------- 1 | In Action 2 | ========= 3 | 4 | This page contains code snippets with summary of zroya's abilities. See :doc:`tutorials/index` for more detailed 5 | introduction. 6 | 7 | Simple Notification 8 | ------------------- 9 | 10 | .. code-block:: python 11 | 12 | import zroya 13 | 14 | zroya.init("Python", "a", "b", "c", "d") 15 | t = zroya.Template(zroya.TemplateType.Text1) 16 | t.setFirstLine("Just one bold line") 17 | zroya.show(t) 18 | 19 | .. figure:: _static/in_action_one_line.png 20 | :alt: Notification with one bold line 21 | 22 | Multiline Notification With Image 23 | --------------------------------- 24 | 25 | .. code-block:: python 26 | 27 | import zroya 28 | 29 | zroya.init("Python", "a", "b", "c", "d") 30 | t = zroya.Template(zroya.TemplateType.ImageAndText4) 31 | t.setFirstLine("First bold line") 32 | t.setSecondLine("Second line is in regular font") 33 | t.setImage("./files/image.png") 34 | zroya.show(t) 35 | 36 | .. figure:: _static/in_action_multiline_image.png 37 | :alt: Notification with one bold, one regular line and an image. 38 | 39 | Attaching callbacks 40 | ------------------- 41 | 42 | .. code-block:: python 43 | 44 | import zroya 45 | import time 46 | 47 | def onClickHandler(notification_id): 48 | print("Clicked!") 49 | 50 | zroya.init("Python", "a", "b", "c", "d") 51 | t = zroya.Template(zroya.TemplateType.Text1) 52 | t.setFirstLine("Click on me, please!") 53 | zroya.show(t, on_click=onClickHandler) 54 | time.sleep(10) 55 | -------------------------------------------------------------------------------- /docs/_sources/index.rst.txt: -------------------------------------------------------------------------------- 1 | Welcome to Zroya's documentation! 2 | ================================= 3 | 4 | Zroya is a Python extension which allows you to create native Windows notifications. 5 | 6 | Installation 7 | ------------ 8 | 9 | Zroya is available from pypi: 10 | 11 | .. code-block:: Bash 12 | 13 | python pip install zroya 14 | 15 | Requirements 16 | ------------ 17 | 18 | There are no requirements for zroya at the moment. 19 | 20 | What next? 21 | ---------- 22 | 23 | Are you interested? Visit :doc:`in_action` and decide, if it is the right package for you. If so, I recommend you to 24 | take a look at :doc:`tutorials/index`. 25 | 26 | .. include:: content.rst 27 | 28 | -------------------------------------------------------------------------------- /docs/_sources/tutorials/callbacks.rst.txt: -------------------------------------------------------------------------------- 1 | Callbacks 2 | ========= 3 | 4 | In the previous part of the tutorial, action buttons were added. But they did nothing. In this tutorial, 5 | I'll teach you how to make them alive. 6 | 7 | But first I have to introduce you into zroya's callback system. Zroya registers four different events: 8 | 9 | * **onClick** - Fired every time user clicks on notification. 10 | * **onAction** - Activated when action button is clicked. 11 | * **onDismiss** - When the notification is dismissed by user or automatically. 12 | * **onFail** - Something went wrong. 13 | 14 | If you want to be informed, when any of them happens, register event handler with **on_** parameters of 15 | :py:func:`zroya.show`. Event handler is nothing more than a regular function taking one, or two parameters. Number of 16 | parameters depends on the event you register for. 17 | 18 | On Click 19 | --------- 20 | 21 | On click handler takes one parameter and it is notification ID. This is the number you get as a return value from 22 | :py:func:`zroya.show`. 23 | 24 | .. code-block:: python 25 | 26 | def onClickHandler(notification_id): 27 | pass 28 | 29 | On Action 30 | --------- 31 | 32 | On Action handler takes two parameters, notification ID and action ID. Action ID is number returned by 33 | :py:meth:`zroya.Template.addAction`. 34 | 35 | .. code-block:: python 36 | 37 | def onActionHandler(notification_id, action_id): 38 | pass 39 | 40 | On Dismiss 41 | ---------- 42 | 43 | On Dismiss handler is function with two parameters. First one is notification ID. The second one is 44 | :py:class:`zroya.DismissReason`. 45 | 46 | .. code-block:: python 47 | 48 | def onDismissHandler(notification_id, reason): 49 | pass 50 | 51 | On Fail 52 | ------- 53 | 54 | Last, on fail handler is function with one parameter, the same as on click callback. The parameter is notification ID 55 | returned from :py:func:`zroya.show`. 56 | 57 | .. code-block:: python 58 | 59 | def onFailHandler(notification_id): 60 | pass 61 | 62 | Adding handlers 63 | --------------- 64 | 65 | Let's go back a bit. In :doc:`template`, we created a notification for simple bot asking user "How are you?". Now 66 | we add response to each of the action button. 67 | 68 | .. code-block:: python 69 | 70 | import zroya 71 | import time 72 | 73 | # Initialization is required. But in real usage, check the return code, please. 74 | zroya.init("python", "a", "b", "c", "d") 75 | 76 | # Template for question 77 | ask_template = zroya.Template(zroya.TemplateType.ImageAndText4) 78 | ask_template.setFirstLine("Hi, I am NotifyBot.") 79 | ask_template.setSecondLine("It is nice to meet you.") 80 | ask_template.setThirdLine("How are you?") 81 | ask_template.setImage("./files/image.png") 82 | ask_template.addAction("I'm OK, I guess") 83 | ask_template.addAction("Fine") 84 | 85 | # Response for Fine 86 | fine_template = zroya.Template(zroya.TemplateType.Text1) 87 | fine_template.setFirstLine("Glad to hear that!") 88 | 89 | # Response for OK 90 | ok_template = zroya.Template(zroya.TemplateType.Text1) 91 | ok_template.setFirstLine("I'm sorry to hear that!") 92 | 93 | 94 | # prepare handler 95 | def onAction(nid, action_id): 96 | global fine_template, ok_template 97 | 98 | if action_id == 0: 99 | zroya.show(ok_template) 100 | else: 101 | zroya.show(fine_template) 102 | 103 | # Show question 104 | zroya.show(ask_template, on_action=onAction) 105 | 106 | # Keep application running, unless onAction handler is never executed. 107 | time.sleep(10) 108 | 109 | Adding images to answers with emoticons, changing sounds etc. would take this to whole new level. You can always play 110 | with it as you wish. 111 | 112 | I owe you one more answer. How did I know that "I'm OK", gets action ID 0 and "Fine" is ID 1? See 113 | :py:meth:`zroya.Template.addAction` ;) Now enjoy the result: 114 | 115 | .. figure:: ../_static/tutorials_callbacks_final.gif 116 | :alt: Process of asking "How are you" followed with the response on me clicking on "I'm fine". 117 | 118 | Pretty impressive, isn't it? 119 | -------------------------------------------------------------------------------- /docs/_sources/tutorials/index.rst.txt: -------------------------------------------------------------------------------- 1 | First steps 2 | =========== 3 | 4 | This tutorial focus only on the basics. It will walk you through setting zroya up, creating template, adding attributes 5 | to it and finally showing a notification. 6 | 7 | Before you follow this tutorial, make sure zroya is installed. See :doc:`installation`. 8 | 9 | .. code-block:: python 10 | 11 | import zroya 12 | 13 | First thing you have to do each time you want to use zroya is to initialize it. This is 14 | required for Windows to associate Python application with notifications. 15 | 16 | .. code-block:: python 17 | 18 | import zroya 19 | 20 | status = zroya.init( 21 | app_name="NotifyBot", 22 | company_name="MyBotCorp", 23 | product_name="NoBo", 24 | sub_product="core", 25 | version="v01" 26 | ) 27 | 28 | if not status: 29 | print("Initialization failed") 30 | 31 | Note that all parameters of :py:func:`zroya.init` are required and they have to be strings. As you see, 32 | :py:func:`zroya.init` returns a boolean status. Always make sure that initialization did not fail. 33 | 34 | Notification templates 35 | ---------------------- 36 | 37 | Now you are ready to create a notification. Each one is based on a :py:class:`zroya.Template`. It holds 38 | all information about the notification - text, image, sounds, etc. 39 | 40 | There are some predefined template types. Think of them as a form you fill blank fields into. The simplest type is 41 | :py:attr:`zroya.TemplateType.Text1`, which have only one field - first line. Filling anything more will result in 42 | errors. 43 | 44 | All types are defined in :py:class:`zroya.TemplateType` class. Select one of them and we will use it to create a 45 | template. 46 | 47 | .. code-block:: python 48 | 49 | # zroya is imported and initialized at this moment 50 | template = zroya.Template(zroya.TemplateType.Text1) 51 | 52 | As you can see, you pass selected template type as a parameter to constructor of :py:class:`zroya.Template`. 53 | 54 | Set it's text 55 | ------------- 56 | 57 | We did create a template. But it does not hold anything. Say you want to show "Hi, how are you?" in it. Following code 58 | will do so: 59 | 60 | .. code-block:: python 61 | 62 | # template is an instance of zroya.Template 63 | template.setFirstLine("Hi, how are you?") 64 | 65 | Show it to the world 66 | -------------------- 67 | 68 | We got there, finally. It is time to show the notification. Use :py:func:`zroya.show` function and pass it **template** 69 | as first parameter: 70 | 71 | .. code-block:: python 72 | 73 | # template is an instance of zroya.Template 74 | zroya.show(template) 75 | 76 | :py:func:`zroya.show` has more parameters, but they don't have to bother you at the moment. We will focus on them in 77 | following steps of this tutorial. 78 | 79 | If everything went right, you should register a notification showing up at the right down corner of your screen. 80 | 81 | .. figure:: ../_static/tutorials_first_steps.png 82 | :alt: Image of notification saying "Hi, how are you?" 83 | 84 | Result of our hard work :) 85 | 86 | Troubleshooting 87 | --------------- 88 | 89 | **Calling** :py:func:`zroya.init` **failed**: This shouldn't happen. Please make sure to `report it`_. It helps me a lot 90 | with debugging and serving you the best product. 91 | 92 | **There is no notification!**: Make sure it is allowed for python (or for any app you are using zroya in) to create 93 | notifications. 94 | 95 | Head to *Settings* **=>** *System* **=>** *Notifications and Actions*. Scroll down and find Python. Set Notifications to 96 | On. 97 | 98 | .. figure:: ../_static/tutorials_first_steps_troubleshooting.gif 99 | :alt: Video showing how to enable notifications for python. 100 | 101 | How to enable notifications. 102 | 103 | .. _report it: https://github.com/malja/zroya/issues/new -------------------------------------------------------------------------------- /docs/_sources/tutorials/installation.rst.txt: -------------------------------------------------------------------------------- 1 | Instalation 2 | =========== 3 | 4 | Installing zroya is pretty straight forward. Just use pypi: 5 | 6 | .. code-block:: bash 7 | 8 | python -m pip install zroya 9 | 10 | Installing from source code 11 | --------------------------- 12 | 13 | For building zroya from source code, Visual C++ Libraries have to be installed in the first place. 14 | 15 | Then clone latest version of zroya: 16 | 17 | .. code-block:: bash 18 | 19 | git clone https://github.com/malja/zroya.git 20 | 21 | And build it with distutils: 22 | 23 | .. code-block:: bash 24 | 25 | python setup.py build -------------------------------------------------------------------------------- /docs/_sources/tutorials/template.rst.txt: -------------------------------------------------------------------------------- 1 | Further on templates 2 | ==================== 3 | 4 | In previous tutorial, we managed to create a notification from template. In this part, we will make the most from 5 | templates. 6 | 7 | Multiple lines 8 | -------------- 9 | 10 | As I said in previous tutorial, not each :py:class:`zroya.TemplateType` supports multiple lines of text. So make 11 | sure you pick the right one - for example :py:attr:`zroya.TemplateType.ImageAndText4`. You may set up to three lines of 12 | text to it. 13 | 14 | .. code-block:: python 15 | 16 | # zroya is imported and initialized 17 | template = zroya.Template(zroya.TemplateType.ImageAndText4) 18 | template.setFirstLine("Hi, I am NotifyBot.") 19 | template.setSecondLine("It is nice to meet you.") 20 | template.setThirdLine("How are you?") 21 | 22 | zroya.show(template) 23 | 24 | At the moment, zroya supports up to three lines - each one is set by it's own function - 25 | :py:meth:`zroya.Template.setFirstLine`, :py:meth:`zroya.Template.setSecondLine` and 26 | :py:meth:`zroya.Template.setThirdLine`. 27 | 28 | .. figure:: ../_static/tutorials_template_three_lines.png 29 | :alt: Image with a notification which contains three lines of text. First line is bold. 30 | 31 | Notification with three lines of text 32 | 33 | Getting the text back 34 | --------------------- 35 | 36 | Except functions for setting text, there are functions for getting it back from template. They are named 37 | :py:meth:`zroya.Template.getFirstLine`, :py:meth:`zroya.Template.getSecondLine` and 38 | :py:meth:`zroya.Template.getThirdLine` respectively. 39 | 40 | We will use template from previous example to get second line back: 41 | 42 | .. code-block:: python 43 | 44 | print(template.getSecondLine()) 45 | #> "It is nice to meet you." 46 | 47 | If there is no such text, empty string is returned. 48 | 49 | Change sound 50 | ------------ 51 | 52 | It is all nice and so, but the sound Windows does when notification is created is sooo boring, right? Let's change it. 53 | 54 | .. code-block:: python 55 | 56 | template.setAudio(zroya.Audio.Call4) 57 | 58 | Sadly, there is no way to play just any sound you want. You can choose from plenty of sounds defined in 59 | :py:class:`zroya.Audio` class. On the other hand, they are available at any Windows station. 60 | 61 | If this is not enough, you can play selected sound in loop until the notification is moved to Action Center, 62 | or until user dismiss it. 63 | 64 | .. code-block:: python 65 | 66 | template.setAudio(zroya.Audio.Call4, zroya.AudioMode.Looping) 67 | 68 | But I wouldn't recommend it. On the other hand, muting notifications may be usable a bit more: 69 | 70 | .. code-block:: python 71 | 72 | template.setAudio(mode=zroya.AudioMode.Silence) 73 | 74 | Expiration time 75 | --------------- 76 | 77 | Notifications will stay in Action Center until you shut the application off or you manually remove them from there. 78 | But some notifications should have shorter lifespan - for example weather reports. There is no use of the old ones. 79 | Beside hiding them from code, :py:meth:`zroya.Template.setExpiration` comes to aid. 80 | 81 | .. code-block:: python 82 | 83 | template.setExpiration(1000) 84 | 85 | It takes a number of milliseconds after which the notification is automatically removed from Action Center. 86 | 87 | Images 88 | ------ 89 | 90 | UI is key to user's heart. Let's make bot more friendly. Add image with :py:meth:`zroya.Template.setImage`. 91 | 92 | .. code-block:: python 93 | 94 | template.setImage("./image.png") 95 | 96 | .. figure:: ../_static/tutorials_template_image.png 97 | :alt: Notification with friendly image of bot. 98 | 99 | Isn't he cute :* 100 | 101 | At this point, we make use of that :py:attr:`zroya.TemplateType.ImageAndText4` template type. For example 102 | with :py:attr:`zroya.TemplateType.Text4`, this function would return False every time, because it does not support 103 | this type. 104 | 105 | Actions 106 | ------- 107 | 108 | One pretty cool feature is adding actions. Those are buttons which can have attached some action to them. When user 109 | click them, event is fired. See :doc:`callbacks`. 110 | 111 | In this example, we add two buttons to respond question notification is asking. What a wonderful time, answering 112 | your own questions :). 113 | 114 | .. code-block:: python 115 | 116 | template.addAction("I'm OK, I guess") 117 | template.addAction("Fine") 118 | 119 | .. figure:: ../_static/tutorials_template_actions.png 120 | :alt: Notification with buttons for answering the question 121 | 122 | Answer the question, please. 123 | 124 | As you probably noticed, they don't do much now. Just dismiss it. We will do something about it in the next tutorial. 125 | 126 | Troubleshooting 127 | --------------- 128 | 129 | **Actions fail to be added**: Actions are one of Windows 8.1+ features. If you have older system, they won't work. -------------------------------------------------------------------------------- /docs/_static/ajax-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/ajax-loader.gif -------------------------------------------------------------------------------- /docs/_static/audio.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 23 | 24 | 25 | 41 | 43 | 44 | -------------------------------------------------------------------------------- /docs/_static/audio/Alarm01.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/audio/Alarm01.wav -------------------------------------------------------------------------------- /docs/_static/audio/Alarm02.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/audio/Alarm02.wav -------------------------------------------------------------------------------- /docs/_static/audio/Alarm03.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/audio/Alarm03.wav -------------------------------------------------------------------------------- /docs/_static/audio/Alarm04.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/audio/Alarm04.wav -------------------------------------------------------------------------------- /docs/_static/audio/Alarm05.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/audio/Alarm05.wav -------------------------------------------------------------------------------- /docs/_static/audio/Alarm06.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/audio/Alarm06.wav -------------------------------------------------------------------------------- /docs/_static/audio/Alarm07.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/audio/Alarm07.wav -------------------------------------------------------------------------------- /docs/_static/audio/Alarm08.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/audio/Alarm08.wav -------------------------------------------------------------------------------- /docs/_static/audio/Alarm09.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/audio/Alarm09.wav -------------------------------------------------------------------------------- /docs/_static/audio/Alarm10.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/audio/Alarm10.wav -------------------------------------------------------------------------------- /docs/_static/audio/Default.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/audio/Default.wav -------------------------------------------------------------------------------- /docs/_static/audio/Email.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/audio/Email.wav -------------------------------------------------------------------------------- /docs/_static/audio/IM.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/audio/IM.wav -------------------------------------------------------------------------------- /docs/_static/audio/Reminder.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/audio/Reminder.wav -------------------------------------------------------------------------------- /docs/_static/audio/Ring01.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/audio/Ring01.wav -------------------------------------------------------------------------------- /docs/_static/audio/Ring02.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/audio/Ring02.wav -------------------------------------------------------------------------------- /docs/_static/audio/Ring03.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/audio/Ring03.wav -------------------------------------------------------------------------------- /docs/_static/audio/Ring04.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/audio/Ring04.wav -------------------------------------------------------------------------------- /docs/_static/audio/Ring05.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/audio/Ring05.wav -------------------------------------------------------------------------------- /docs/_static/audio/Ring06.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/audio/Ring06.wav -------------------------------------------------------------------------------- /docs/_static/audio/Ring07.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/audio/Ring07.wav -------------------------------------------------------------------------------- /docs/_static/audio/Ring08.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/audio/Ring08.wav -------------------------------------------------------------------------------- /docs/_static/audio/Ring09.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/audio/Ring09.wav -------------------------------------------------------------------------------- /docs/_static/audio/Ring10.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/audio/Ring10.wav -------------------------------------------------------------------------------- /docs/_static/comment-bright.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/comment-bright.png -------------------------------------------------------------------------------- /docs/_static/comment-close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/comment-close.png -------------------------------------------------------------------------------- /docs/_static/comment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/comment.png -------------------------------------------------------------------------------- /docs/_static/css/styles.css: -------------------------------------------------------------------------------- 1 | iframe { 2 | border: none; 3 | height: 60px; 4 | } -------------------------------------------------------------------------------- /docs/_static/custom.css: -------------------------------------------------------------------------------- 1 | /* This file intentionally left blank. */ 2 | -------------------------------------------------------------------------------- /docs/_static/desktop.ini: -------------------------------------------------------------------------------- 1 | [LocalizedFileNames] 2 | Windows Default.wav=@%windir%\system32\mmres.dll,-715 3 | -------------------------------------------------------------------------------- /docs/_static/documentation_options.js: -------------------------------------------------------------------------------- 1 | var DOCUMENTATION_OPTIONS = { 2 | URL_ROOT: '', 3 | VERSION: '0.2.2', 4 | LANGUAGE: 'None', 5 | COLLAPSE_INDEX: false, 6 | FILE_SUFFIX: '.html', 7 | HAS_SOURCE: true, 8 | SOURCELINK_SUFFIX: '.txt' 9 | }; -------------------------------------------------------------------------------- /docs/_static/down-pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/down-pressed.png -------------------------------------------------------------------------------- /docs/_static/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/down.png -------------------------------------------------------------------------------- /docs/_static/example_full_features.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/example_full_features.png -------------------------------------------------------------------------------- /docs/_static/example_full_features_action.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/example_full_features_action.png -------------------------------------------------------------------------------- /docs/_static/example_full_features_attribution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/example_full_features_attribution.png -------------------------------------------------------------------------------- /docs/_static/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/file.png -------------------------------------------------------------------------------- /docs/_static/in_action_multiline_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/in_action_multiline_image.png -------------------------------------------------------------------------------- /docs/_static/in_action_one_line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/in_action_one_line.png -------------------------------------------------------------------------------- /docs/_static/minus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/minus.png -------------------------------------------------------------------------------- /docs/_static/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/plus.png -------------------------------------------------------------------------------- /docs/_static/pygments.css: -------------------------------------------------------------------------------- 1 | .highlight .hll { background-color: #ffffcc } 2 | .highlight { background: #eeffcc; } 3 | .highlight .c { color: #408090; font-style: italic } /* Comment */ 4 | .highlight .err { border: 1px solid #FF0000 } /* Error */ 5 | .highlight .k { color: #007020; font-weight: bold } /* Keyword */ 6 | .highlight .o { color: #666666 } /* Operator */ 7 | .highlight .ch { color: #408090; font-style: italic } /* Comment.Hashbang */ 8 | .highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */ 9 | .highlight .cp { color: #007020 } /* Comment.Preproc */ 10 | .highlight .cpf { color: #408090; font-style: italic } /* Comment.PreprocFile */ 11 | .highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */ 12 | .highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ 13 | .highlight .gd { color: #A00000 } /* Generic.Deleted */ 14 | .highlight .ge { font-style: italic } /* Generic.Emph */ 15 | .highlight .gr { color: #FF0000 } /* Generic.Error */ 16 | .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 17 | .highlight .gi { color: #00A000 } /* Generic.Inserted */ 18 | .highlight .go { color: #333333 } /* Generic.Output */ 19 | .highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ 20 | .highlight .gs { font-weight: bold } /* Generic.Strong */ 21 | .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 22 | .highlight .gt { color: #0044DD } /* Generic.Traceback */ 23 | .highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ 24 | .highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ 25 | .highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ 26 | .highlight .kp { color: #007020 } /* Keyword.Pseudo */ 27 | .highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ 28 | .highlight .kt { color: #902000 } /* Keyword.Type */ 29 | .highlight .m { color: #208050 } /* Literal.Number */ 30 | .highlight .s { color: #4070a0 } /* Literal.String */ 31 | .highlight .na { color: #4070a0 } /* Name.Attribute */ 32 | .highlight .nb { color: #007020 } /* Name.Builtin */ 33 | .highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ 34 | .highlight .no { color: #60add5 } /* Name.Constant */ 35 | .highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ 36 | .highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ 37 | .highlight .ne { color: #007020 } /* Name.Exception */ 38 | .highlight .nf { color: #06287e } /* Name.Function */ 39 | .highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ 40 | .highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ 41 | .highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ 42 | .highlight .nv { color: #bb60d5 } /* Name.Variable */ 43 | .highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ 44 | .highlight .w { color: #bbbbbb } /* Text.Whitespace */ 45 | .highlight .mb { color: #208050 } /* Literal.Number.Bin */ 46 | .highlight .mf { color: #208050 } /* Literal.Number.Float */ 47 | .highlight .mh { color: #208050 } /* Literal.Number.Hex */ 48 | .highlight .mi { color: #208050 } /* Literal.Number.Integer */ 49 | .highlight .mo { color: #208050 } /* Literal.Number.Oct */ 50 | .highlight .sa { color: #4070a0 } /* Literal.String.Affix */ 51 | .highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ 52 | .highlight .sc { color: #4070a0 } /* Literal.String.Char */ 53 | .highlight .dl { color: #4070a0 } /* Literal.String.Delimiter */ 54 | .highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ 55 | .highlight .s2 { color: #4070a0 } /* Literal.String.Double */ 56 | .highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ 57 | .highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ 58 | .highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ 59 | .highlight .sx { color: #c65d09 } /* Literal.String.Other */ 60 | .highlight .sr { color: #235388 } /* Literal.String.Regex */ 61 | .highlight .s1 { color: #4070a0 } /* Literal.String.Single */ 62 | .highlight .ss { color: #517918 } /* Literal.String.Symbol */ 63 | .highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ 64 | .highlight .fm { color: #06287e } /* Name.Function.Magic */ 65 | .highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ 66 | .highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ 67 | .highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ 68 | .highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */ 69 | .highlight .il { color: #208050 } /* Literal.Number.Integer.Long */ -------------------------------------------------------------------------------- /docs/_static/tutorials_callbacks_final.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/tutorials_callbacks_final.gif -------------------------------------------------------------------------------- /docs/_static/tutorials_first_steps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/tutorials_first_steps.png -------------------------------------------------------------------------------- /docs/_static/tutorials_first_steps_troubleshooting.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/tutorials_first_steps_troubleshooting.gif -------------------------------------------------------------------------------- /docs/_static/tutorials_template_actions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/tutorials_template_actions.png -------------------------------------------------------------------------------- /docs/_static/tutorials_template_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/tutorials_template_image.png -------------------------------------------------------------------------------- /docs/_static/tutorials_template_three_lines.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/tutorials_template_three_lines.png -------------------------------------------------------------------------------- /docs/_static/up-pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/up-pressed.png -------------------------------------------------------------------------------- /docs/_static/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/_static/up.png -------------------------------------------------------------------------------- /docs/commiting.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | Committing to zroya — Zroya 0.2 documentation 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 |
30 |
31 |
32 | 33 |
34 |

Committing to zroya

35 |
36 |

Changes in C files

37 |
    38 |
  1. Build Python extension from C source

    39 |
    40 |

    > python setup.py build

    41 |

    Make sure there are no errors.

    42 |
    43 |
  2. 44 |
  3. Test it with existing tests

    45 |
    46 |

    > python setup.py test

    47 |

    Make sure all tests passed

    48 |
    49 |
  4. 50 |
  5. Write your own tests when necessary.

    51 |
  6. 52 |
  7. Change documentation. See Changes in Documentation

    53 |
  8. 54 |
  9. Make stubs

    55 |
    56 |

    > python setup.py stubs

    57 |
    58 |
  10. 59 |
60 |
61 |
62 |

Changes in Python files

63 |
    64 |
  1. Test your changes with existing tests

    65 |
    66 |

    > python setup.py test

    67 |
    68 |
  2. 69 |
  3. Write your own tests when necessary.

    70 |
  4. 71 |
  5. Change documentation. See Changes in Documentation

    72 |
  6. 73 |
  7. Make stubs

    74 |
    75 |

    > python setup.py stubs

    76 |
    77 |
  8. 78 |
79 |
80 |
81 |

Changes in documentation

82 |
    83 |
  1. Build html documentation

    84 |
    85 |

    > python setup.py docs

    86 |
    87 |
  2. 88 |
89 |
90 |
91 | 92 | 93 |
94 |
95 |
96 | 134 |
135 |
136 | 147 | 148 | 149 | 150 | 151 | 152 | -------------------------------------------------------------------------------- /docs/committing.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | Committing to zroya — Zroya 0.2.2 documentation 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 |
31 |
32 |
33 | 34 |
35 |

Committing to zroya

36 |

This page is work in progress.

37 |
38 |

Changes in C files

39 |
    40 |
  1. Build Python extension from C source.
  2. 41 |
42 |
python setup.py build
 43 | 
44 |
45 |

Make sure there are no errors.

46 |
    47 |
  1. Run current tests.
  2. 48 |
49 |
python setup.py test
 50 | 
51 |
52 |
    53 |
  1. Write your own tests when necessary.
  2. 54 |
  3. Change documentation. See Changes in documentation section.
  4. 55 |
  5. Make stubs
  6. 56 |
57 |
python setup.py stubs
 58 | 
59 |
60 |
61 |
62 |

Changes in Python files

63 |
    64 |
  1. Test your changes with existing tests
  2. 65 |
66 |
python setup.py test
 67 | 
68 |
69 |
    70 |
  1. Write your own tests when necessary.
  2. 71 |
  3. Change documentation. See Changes in documentation section.
  4. 72 |
  5. Make stubs
  6. 73 |
74 |
python setup.py stubs
 75 | 
76 |
77 |
78 |
79 |

Changes in documentation

80 |
    81 |
  1. Build html documentation.
  2. 82 |
83 |
python setup.py docs
 84 | 
85 |
86 |
87 |
88 | 89 | 90 |
91 |
92 |
93 | 139 |
140 |
141 | 152 | 153 | 154 | 155 | 156 | 157 | -------------------------------------------------------------------------------- /docs/content.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | Tutorial — Zroya 0.2.2 documentation 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 |
30 |
31 |
32 | 33 | 88 | 89 | 90 |
91 |
92 |
93 | 133 |
134 |
135 | 146 | 147 | 148 | 149 | 150 | 151 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | Welcome to Zroya’s documentation! — Zroya 0.2.2 documentation 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 |
31 |
32 |
33 | 34 |
35 |

Welcome to Zroya’s documentation!

36 |

Zroya is a Python extension which allows you to create native Windows notifications.

37 |
38 |

Installation

39 |

Zroya is available from pypi:

40 |
python pip install zroya
 41 | 
42 |
43 |
44 |
45 |

Requirements

46 |

There are no requirements for zroya at the moment.

47 |
48 |
49 |

What next?

50 |

Are you interested? Visit In Action and decide, if it is the right package for you. If so, I recommend you to 51 | take a look at First steps.

52 |
53 |
54 | 109 | 110 | 111 |
112 |
113 |
114 | 155 |
156 |
157 | 168 | 169 | 170 | 171 | 172 | 173 | -------------------------------------------------------------------------------- /docs/objects.inv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs/objects.inv -------------------------------------------------------------------------------- /docs/py-modindex.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | Python Module Index — Zroya 0.2.2 documentation 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 30 | 31 | 32 | 33 | 34 | 35 |
36 |
37 |
38 |
39 | 40 | 41 |

Python Module Index

42 | 43 |
44 | z 45 |
46 | 47 | 48 | 49 | 51 | 52 | 53 | 56 |
 
50 | z
54 | zroya 55 |
57 | 58 | 59 |
60 |
61 |
62 | 95 |
96 |
97 | 105 | 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /docs/search.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | Search — Zroya 0.2.2 documentation 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 |
37 |
38 |
39 |
40 | 41 |

Search

42 |
43 | 44 |

45 | Please activate JavaScript to enable the search 46 | functionality. 47 |

48 |
49 |

50 | From here you can search these documents. Enter your search 51 | words into the box below and click "search". Note that the search 52 | function will automatically search for all of the words. Pages 53 | containing fewer words won't appear in the result list. 54 |

55 |
56 | 57 | 58 | 59 |
60 | 61 |
62 | 63 |
64 | 65 |
66 |
67 |
68 | 89 |
90 |
91 | 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /docs/searchindex.js: -------------------------------------------------------------------------------- 1 | Search.setIndex({docnames:["committing","content","documentation","in_action","index","tutorials/callbacks","tutorials/index","tutorials/installation","tutorials/template"],envversion:53,filenames:["committing.rst","content.rst","documentation.rst","in_action.rst","index.rst","tutorials\\callbacks.rst","tutorials\\index.rst","tutorials\\installation.rst","tutorials\\template.rst"],objects:{"":{zroya:[2,0,0,"-"]},"zroya.Audio":{Alarm10:[2,2,1,""],Alarm2:[2,2,1,""],Alarm3:[2,2,1,""],Alarm4:[2,2,1,""],Alarm5:[2,2,1,""],Alarm6:[2,2,1,""],Alarm7:[2,2,1,""],Alarm8:[2,2,1,""],Alarm9:[2,2,1,""],Alarm:[2,2,1,""],Call10:[2,2,1,""],Call2:[2,2,1,""],Call3:[2,2,1,""],Call4:[2,2,1,""],Call5:[2,2,1,""],Call6:[2,2,1,""],Call7:[2,2,1,""],Call8:[2,2,1,""],Call9:[2,2,1,""],Call:[2,2,1,""],Default:[2,2,1,""],IM:[2,2,1,""],Mail:[2,2,1,""],Reminder:[2,2,1,""]},"zroya.AudioMode":{Default:[2,2,1,""],Loop:[2,2,1,""],Silence:[2,2,1,""]},"zroya.DismissReason":{App:[2,2,1,""],Expired:[2,2,1,""],User:[2,2,1,""]},"zroya.Template":{addAction:[2,3,1,""],getAttribution:[2,3,1,""],getAudio:[2,3,1,""],getAudioMode:[2,3,1,""],getExpiration:[2,3,1,""],getFirstLine:[2,3,1,""],getImage:[2,3,1,""],getSecondLine:[2,3,1,""],getThirdLine:[2,3,1,""],setAttribution:[2,3,1,""],setAudio:[2,3,1,""],setExpiration:[2,3,1,""],setFirstLine:[2,3,1,""],setImage:[2,3,1,""],setSecondLine:[2,3,1,""],setThirdLine:[2,3,1,""]},"zroya.TemplateType":{ImageAndText1:[2,2,1,""],ImageAndText2:[2,2,1,""],ImageAndText3:[2,2,1,""],ImageAndText4:[2,2,1,""],Text1:[2,2,1,""],Text2:[2,2,1,""],Text3:[2,2,1,""],Text4:[2,2,1,""]},zroya:{Audio:[2,1,1,""],AudioMode:[2,1,1,""],DismissReason:[2,1,1,""],Template:[2,1,1,""],TemplateType:[2,1,1,""],hide:[2,4,1,""],init:[2,4,1,""],show:[2,4,1,""]}},objnames:{"0":["py","module","Python module"],"1":["py","class","Python class"],"2":["py","attribute","Python attribute"],"3":["py","method","Python method"],"4":["py","function","Python function"]},objtypes:{"0":"py:module","1":"py:class","2":"py:attribute","3":"py:method","4":"py:function"},terms:{"boolean":6,"case":2,"class":[2,6,8],"default":2,"final":6,"function":[1,4,5,6,8],"import":[3,5,6,8],"int":2,"new":5,"return":[2,5,6,8],"true":2,Adding:[1,4],And:7,Are:4,But:[5,6,8],For:[7,8],One:[2,8],The:[2,5,6],Then:7,There:[4,6,8],Use:6,With:[1,4],abil:3,about:[6,8],accept:2,across:2,action:[1,2,4,6],action_id:5,activ:[2,5],add:[2,5,8],addact:[2,5,8],added:[5,8],adding:[6,8],after:8,aid:8,alarm10:2,alarm2:2,alarm3:2,alarm4:2,alarm5:2,alarm6:2,alarm7:2,alarm8:2,alarm9:2,alarm:2,aliv:5,all:[2,6,8],allow:[4,6],alwai:[5,6],ani:[2,5,6,8],annoi:[],answer:[5,8],anyth:6,api:[1,4],app:[2,6],app_nam:[2,6],applic:[2,5,6,8],arg:2,ask:[5,8],ask_templ:5,associ:6,attach:[1,4,8],attempt:2,attent:2,attribut:[2,6],audio:[1,4,8],audiomod:8,automat:[5,8],avail:[2,4,8],back:[1,2,4,5],base:[2,6],basic:6,becaus:8,befor:[2,6],being:2,besid:8,best:6,bit:[5,8],blank:6,bold:[2,3],bool:2,bore:8,bot:[5,8],bother:6,bright:[],build:[0,7],button:[2,5,8],call10:2,call2:2,call3:2,call4:[2,8],call5:2,call6:2,call7:2,call8:2,call9:2,call:[2,6],callabl:2,callback:[1,2,4,8],can:[2,5,6,8],caus:2,center:[2,8],chang:[1,4,5],check:5,choos:8,click:[1,2,3,4,8],clone:7,code:[1,3,4,5,6,8],com:7,come:8,commit:[1,4],company_nam:[2,6],compar:2,complet:2,configur:2,constructor:[2,6],contain:[2,3],cool:8,core:6,corner:6,correspond:2,count:2,creat:[2,4,5,6,8],current:[0,2],cute:8,debug:6,decid:4,def:[3,5],defin:[2,6,8],depend:5,descript:2,detail:3,did:[5,6],differ:[2,5],dismiss:[1,2,4,8],dismissreason:[1,4,5],distutil:7,doc:0,document:1,doe:[2,6,8],don:[6,8],down:6,due:2,each:[2,5,6,8],either:2,els:5,emoticon:5,empti:[2,8],enabl:6,enjoi:5,enough:8,enumer:2,error:[0,2,6],etc:[5,6],even:2,event:[2,5,8],everi:[5,8],everyth:6,exampl:[2,8],except:8,execut:5,exist:[0,2],expir:[1,2,4],explicit:2,explicitli:2,extens:[0,4],fail:[1,4,6,8],fals:[2,8],fart:[],featur:[2,8],field:6,file:[1,3,4,5],filenotfounderror:2,fill:6,find:6,fine:[5,8],fine_templ:5,fire:[2,5,8],first:[1,2,3,4,5,7],focu:6,follow:[2,6],font:3,form:6,forward:7,four:5,friendli:8,from:[0,1,2,4,5,8],further:[1,4,5],gener:2,get:[1,2,4,5],getattribut:2,getaudio:2,getaudiomod:2,getexpir:2,getfirstlin:[2,8],getimag:2,getsecondlin:[2,8],getthirdlin:[2,8],git:7,github:7,glad:5,global:5,got:[2,6],guess:[5,8],hand:[2,8],handler:[1,2,4],happen:[5,6],hard:6,has:[2,6],have:[5,6,7,8],head:6,hear:5,heart:8,help:6,hid:2,hidden:2,hide:[2,8],highlight:2,hold:[2,6],how:[2,5,6,8],html:0,http:7,imag:[1,2,4,5,6],imageandtext1:2,imageandtext2:2,imageandtext3:2,imageandtext4:[2,3,5,8],impress:5,index:2,inform:[5,6],init:[2,3,5,6],initi:[2,5,6,8],instal:[1,6],instanc:[2,6],interest:4,introduc:5,introduct:3,isn:[5,8],its:2,just:[3,7,8],keep:5,kei:8,know:5,label:2,larg:2,last:5,latest:7,leav:2,let:[5,8],level:5,librari:7,lifespan:8,line:[1,2,3,4,6],look:4,loop:[2,8],lot:6,mai:[2,8],mail:2,make:[0,5,6,8],malja:7,manag:8,manipul:2,manual:8,mean:2,meet:[5,8],method:2,millisecond:[2,8],mode:[2,8],modern:2,modul:2,moment:[4,6,8],more:[3,5,6,8],most:8,move:[2,8],much:8,multilin:[1,4],multipl:[1,4],mute:8,mybotcorp:6,name:[2,8],nativ:4,necessari:0,never:5,newer:2,next:8,nice:[5,8],nid:[2,5],nobo:6,note:[2,6],noth:5,notic:8,notif:[1,2,4,5,8],notification_id:[3,5],notifybot:[5,6,8],now:[5,6,8],number:[2,5,8],obtain:2,occur:2,off:8,ok_templ:5,old:8,older:8,on_:[2,5],on_act:[2,5],on_click:[2,3],on_dismiss:2,on_fail:2,onact:[2,5],onactionhandl:5,onc:2,onclick:[2,5],onclickhandl:[3,5],ondismiss:[2,5],ondismisshandl:5,one:[2,3,5,6,8],ones:8,onfail:[2,5],onfailhandl:5,onli:[2,6],other:[2,8],otherwis:2,our:6,owe:5,own:[0,2,8],packag:4,page:[0,3],paramet:[2,5,6],part:[2,5,8],pass:[2,5,6],path:2,pick:8,pip:[4,7],place:7,plai:[2,5,8],playback:2,pleas:[3,5,6,8],plenti:8,png:[3,5,8],point:8,posit:2,possibl:2,predefin:[2,6],prepar:5,pretti:[5,7,8],previou:[5,8],print:[2,3,6,8],probabl:8,product:6,product_nam:[2,6],progress:0,pypi:[4,7],python:[1,3,4,5,6,7],question:[5,8],rage:[],rais:2,randomli:2,readi:6,real:5,reason:[2,5],recommend:[4,8],record:[],regist:[2,5,6],regular:[2,3,5],remind:2,remov:[2,8],report:[6,8],repres:2,requir:[2,5,6],respect:8,respond:8,respons:5,result:[5,6],right:[4,6,8],run:[0,5],sadli:8,sai:6,said:8,same:5,screen:[2,6],scroll:6,second:[2,3,5,8],section:0,see:[0,2,3,5,6,8],select:[2,6,8],serv:6,set:[1,2,4,8],setattribut:2,setaudio:[2,8],setexpir:[2,8],setfirstlin:[2,3,5,6,8],setimag:[2,3,5,8],setsecondlin:[2,3,5,8],setthirdlin:[2,5,8],setup:[0,7],shorter:8,should:[2,6,8],shouldn:6,show:[1,2,3,4,5,8],shown:2,shut:8,side:[],silenc:[2,8],simpl:[1,4,5],simplest:6,singl:2,sleep:[3,5],snippet:3,some:[6,8],someth:[5,8],sooo:8,sorri:5,sound:[1,2,4,5,6],sourc:[0,1,4],stai:8,station:8,statu:6,step:[1,3,4],str:2,straight:7,string:[2,6,8],stub:0,sub_product:[2,6],success:2,summari:3,support:[2,8],sure:[0,6,8],system:[2,5,6,8],take:[4,5,8],teach:5,templat:[1,3,4,5],templatetyp:[3,5,6,8],test:0,text1:[2,3,5,6],text2:2,text3:2,text4:[2,8],text:[1,2,4],than:5,thei:[5,6,8],them:[5,6,8],thi:[0,2,3,5,6,8],thing:6,think:6,third:2,those:8,three:[2,8],through:[2,6],time:[1,2,3,4,5,6],toast:2,touch:2,trigger:2,troubleshoot:[1,4],tutori:[5,6,8],two:[2,5,8],type:[2,6,8],typeerror:2,uniqu:2,unless:5,unsupport:2,until:[2,8],usabl:8,usag:5,use:[6,7,8],used:2,user:[2,5,8],using:[2,6],v01:6,valid:2,valu:[2,5],vari:2,version:[2,6,7],visit:4,visual:7,wai:8,walk:6,want:[5,6,8],weather:8,went:[5,6],were:5,what:8,when:[0,2,5,8],which:[4,6,8],whole:5,window:[2,4,6,8],winsoundev:2,wish:5,won:8,wonder:8,work:[0,6,8],world:[1,4],would:[5,8],wouldn:8,wrap:2,write:0,wrong:5,yesterdai:[],you:[2,4,5,6,8],your:[0,6,8],zero:2,zroya:[1,2,3,5,6,7,8]},titles:["Committing to zroya","Tutorial","API Documentation","In Action","Welcome to Zroya\u2019s documentation!","Callbacks","First steps","Instalation","Further on templates"],titleterms:{"function":2,Adding:5,With:3,action:[3,5,8],api:2,attach:3,audio:2,audiomod:2,back:8,callback:[3,5],chang:[0,8],click:5,code:7,commit:0,dismiss:5,dismissreason:2,document:[0,2,4],expir:8,fail:5,file:0,first:6,from:7,further:8,get:8,handler:5,imag:[3,8],instal:[4,7],line:8,multilin:3,multipl:8,next:4,notif:[3,6],python:0,requir:4,set:6,show:6,simpl:3,sound:8,sourc:7,step:6,templat:[2,6,8],templatetyp:2,text:[6,8],time:8,troubleshoot:[6,8],tutori:[1,4],welcom:4,what:4,world:6,zroya:[0,4]}}) -------------------------------------------------------------------------------- /docs/tutorials/installation.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | Instalation — Zroya 0.2.2 documentation 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |
32 |
33 |
34 | 35 |
36 |

Instalation

37 |

Installing zroya is pretty straight forward. Just use pypi:

38 |
python -m pip install zroya
 39 | 
40 |
41 |
42 |

Installing from source code

43 |

For building zroya from source code, Visual C++ Libraries have to be installed in the first place.

44 |

Then clone latest version of zroya:

45 |
git clone https://github.com/malja/zroya.git
 46 | 
47 |
48 |

And build it with distutils:

49 |
python setup.py build
 50 | 
51 |
52 |
53 |
54 | 55 | 56 |
57 |
58 |
59 | 104 |
105 |
106 | 117 | 118 | 119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /docs_source/sphinx/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | set SPHINXPROJ=Zroya 13 | 14 | if "%1" == "" goto help 15 | 16 | %SPHINXBUILD% >NUL 2>NUL 17 | if errorlevel 9009 ( 18 | echo. 19 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 20 | echo.installed, then set the SPHINXBUILD environment variable to point 21 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 22 | echo.may add the Sphinx directory to PATH. 23 | echo. 24 | echo.If you don't have Sphinx installed, grab it from 25 | echo.http://sphinx-doc.org/ 26 | exit /b 1 27 | ) 28 | 29 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 30 | goto end 31 | 32 | :help 33 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 34 | 35 | :end 36 | popd 37 | -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/audio.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 23 | 24 | 25 | 41 | 43 | 44 | -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/audio/Alarm01.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs_source/sphinx/source/_static/audio/Alarm01.wav -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/audio/Alarm02.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs_source/sphinx/source/_static/audio/Alarm02.wav -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/audio/Alarm03.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs_source/sphinx/source/_static/audio/Alarm03.wav -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/audio/Alarm04.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs_source/sphinx/source/_static/audio/Alarm04.wav -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/audio/Alarm05.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs_source/sphinx/source/_static/audio/Alarm05.wav -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/audio/Alarm06.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs_source/sphinx/source/_static/audio/Alarm06.wav -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/audio/Alarm07.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs_source/sphinx/source/_static/audio/Alarm07.wav -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/audio/Alarm08.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs_source/sphinx/source/_static/audio/Alarm08.wav -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/audio/Alarm09.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs_source/sphinx/source/_static/audio/Alarm09.wav -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/audio/Alarm10.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs_source/sphinx/source/_static/audio/Alarm10.wav -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/audio/Default.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs_source/sphinx/source/_static/audio/Default.wav -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/audio/Email.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs_source/sphinx/source/_static/audio/Email.wav -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/audio/IM.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs_source/sphinx/source/_static/audio/IM.wav -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/audio/Reminder.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs_source/sphinx/source/_static/audio/Reminder.wav -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/audio/Ring01.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs_source/sphinx/source/_static/audio/Ring01.wav -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/audio/Ring02.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs_source/sphinx/source/_static/audio/Ring02.wav -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/audio/Ring03.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs_source/sphinx/source/_static/audio/Ring03.wav -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/audio/Ring04.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs_source/sphinx/source/_static/audio/Ring04.wav -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/audio/Ring05.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs_source/sphinx/source/_static/audio/Ring05.wav -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/audio/Ring06.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs_source/sphinx/source/_static/audio/Ring06.wav -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/audio/Ring07.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs_source/sphinx/source/_static/audio/Ring07.wav -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/audio/Ring08.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs_source/sphinx/source/_static/audio/Ring08.wav -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/audio/Ring09.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs_source/sphinx/source/_static/audio/Ring09.wav -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/audio/Ring10.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs_source/sphinx/source/_static/audio/Ring10.wav -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/css/styles.css: -------------------------------------------------------------------------------- 1 | iframe { 2 | border: none; 3 | height: 60px; 4 | } -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/desktop.ini: -------------------------------------------------------------------------------- 1 | [LocalizedFileNames] 2 | Windows Default.wav=@%windir%\system32\mmres.dll,-715 3 | -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/example_full_features.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs_source/sphinx/source/_static/example_full_features.png -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/example_full_features_action.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs_source/sphinx/source/_static/example_full_features_action.png -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/example_full_features_attribution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs_source/sphinx/source/_static/example_full_features_attribution.png -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/in_action_multiline_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs_source/sphinx/source/_static/in_action_multiline_image.png -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/in_action_one_line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs_source/sphinx/source/_static/in_action_one_line.png -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/tutorials_callbacks_final.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs_source/sphinx/source/_static/tutorials_callbacks_final.gif -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/tutorials_first_steps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs_source/sphinx/source/_static/tutorials_first_steps.png -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/tutorials_first_steps_troubleshooting.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs_source/sphinx/source/_static/tutorials_first_steps_troubleshooting.gif -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/tutorials_template_actions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs_source/sphinx/source/_static/tutorials_template_actions.png -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/tutorials_template_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs_source/sphinx/source/_static/tutorials_template_image.png -------------------------------------------------------------------------------- /docs_source/sphinx/source/_static/tutorials_template_three_lines.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/docs_source/sphinx/source/_static/tutorials_template_three_lines.png -------------------------------------------------------------------------------- /docs_source/sphinx/source/committing.rst: -------------------------------------------------------------------------------- 1 | Committing to zroya 2 | =================== 3 | 4 | This page is work in progress. 5 | 6 | Changes in C files 7 | ------------------ 8 | 9 | 1. Build Python extension from C source. 10 | 11 | .. code-block:: bash 12 | 13 | python setup.py build 14 | 15 | Make sure there are no errors. 16 | 17 | 2. Run current tests. 18 | 19 | .. code-block:: bash 20 | 21 | python setup.py test 22 | 23 | 3. Write your own tests when necessary. 24 | 25 | 4. Change documentation. See :ref:`changes_in_documentation` section. 26 | 27 | 5. Make stubs 28 | 29 | .. code-block:: bash 30 | 31 | python setup.py stubs 32 | 33 | Changes in Python files 34 | ----------------------- 35 | 36 | 1. Test your changes with existing tests 37 | 38 | .. code-block:: bash 39 | 40 | python setup.py test 41 | 42 | 2. Write your own tests when necessary. 43 | 44 | 3. Change documentation. See :ref:`changes_in_documentation` section. 45 | 46 | 4. Make stubs 47 | 48 | .. code-block:: bash 49 | 50 | python setup.py stubs 51 | 52 | .. _changes_in_documentation: 53 | 54 | Changes in documentation 55 | ------------------------ 56 | 57 | 1. Build html documentation. 58 | 59 | .. code-block:: bash 60 | 61 | python setup.py docs 62 | -------------------------------------------------------------------------------- /docs_source/sphinx/source/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import sys 4 | import os 5 | sys.path.append(os.path.abspath("../../../zroya")) 6 | 7 | import version as zroya_version 8 | 9 | # 10 | # Configuration file for the Sphinx documentation builder. 11 | # 12 | # This file does only contain a selection of the most common options. For a 13 | # full list see the documentation: 14 | # http://www.sphinx-doc.org/en/stable/config 15 | 16 | # -- Path setup -------------------------------------------------------------- 17 | 18 | # If extensions (or modules to document with autodoc) are in another directory, 19 | # add these directories to sys.path here. If the directory is relative to the 20 | # documentation root, use os.path.abspath to make it absolute, like shown here. 21 | # 22 | # import os 23 | # import sys 24 | # sys.path.insert(0, os.path.abspath('.')) 25 | 26 | 27 | # -- Project information ----------------------------------------------------- 28 | 29 | project = 'Zroya' 30 | copyright = '2018, Jan Malčák' 31 | author = 'Jan Malčák' 32 | 33 | # The short X.Y version 34 | version = zroya_version.__version__ 35 | # The full version, including alpha/beta/rc tags 36 | release = zroya_version.__release__ 37 | 38 | 39 | # -- General configuration --------------------------------------------------- 40 | 41 | # If your documentation needs a minimal Sphinx version, state it here. 42 | # 43 | # needs_sphinx = '1.0' 44 | 45 | # Add any Sphinx extension module names here, as strings. They can be 46 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 47 | # ones. 48 | extensions = [ 49 | 'sphinx.ext.autodoc', 50 | 'sphinx.ext.coverage', 51 | 'sphinxcontrib.fulltoc', 52 | ] 53 | 54 | # Add any paths that contain templates here, relative to this directory. 55 | templates_path = ['_templates'] 56 | 57 | # The suffix(es) of source filenames. 58 | # You can specify multiple suffix as a list of string: 59 | # 60 | # source_suffix = ['.rst', '.md'] 61 | source_suffix = '.rst' 62 | 63 | # The master toctree document. 64 | master_doc = 'index' 65 | 66 | # The language for content autogenerated by Sphinx. Refer to documentation 67 | # for a list of supported languages. 68 | # 69 | # This is also used if you do content translation via gettext catalogs. 70 | # Usually you set "language" from the command line for these cases. 71 | language = None 72 | 73 | # List of patterns, relative to source directory, that match files and 74 | # directories to ignore when looking for source files. 75 | # This pattern also affects html_static_path and html_extra_path . 76 | exclude_patterns = [] 77 | 78 | # The name of the Pygments (syntax highlighting) style to use. 79 | pygments_style = 'sphinx' 80 | 81 | 82 | # -- Options for HTML output ------------------------------------------------- 83 | 84 | # The theme to use for HTML and HTML Help pages. See the documentation for 85 | # a list of builtin themes. 86 | # 87 | html_theme = 'alabaster' 88 | 89 | # Theme options are theme-specific and customize the look and feel of a theme 90 | # further. For a list of options available for each theme, see the 91 | # documentation. 92 | # 93 | # html_theme_options = {} 94 | 95 | # Add any paths that contain custom static files (such as style sheets) here, 96 | # relative to this directory. They are copied after the builtin static files, 97 | # so a file named "default.css" will overwrite the builtin "default.css". 98 | html_static_path = ['_static'] 99 | 100 | # Custom sidebar templates, must be a dictionary that maps document names 101 | # to template names. 102 | # 103 | # The default sidebars (for documents that don't match any pattern) are 104 | # defined by theme itself. Builtin themes are using these templates by 105 | # default: ``['localtoc.html', 'relations.html', 'sourcelink.html', 106 | # 'searchbox.html']``. 107 | # 108 | # html_sidebars = {} 109 | 110 | 111 | # -- Options for HTMLHelp output --------------------------------------------- 112 | 113 | # Output file base name for HTML help builder. 114 | htmlhelp_basename = 'Zroyadoc' 115 | 116 | 117 | # -- Options for LaTeX output ------------------------------------------------ 118 | 119 | latex_elements = { 120 | # The paper size ('letterpaper' or 'a4paper'). 121 | # 122 | # 'papersize': 'letterpaper', 123 | 124 | # The font size ('10pt', '11pt' or '12pt'). 125 | # 126 | # 'pointsize': '10pt', 127 | 128 | # Additional stuff for the LaTeX preamble. 129 | # 130 | # 'preamble': '', 131 | 132 | # Latex figure (float) alignment 133 | # 134 | # 'figure_align': 'htbp', 135 | } 136 | 137 | # Grouping the document tree into LaTeX files. List of tuples 138 | # (source start file, target name, title, 139 | # author, documentclass [howto, manual, or own class]). 140 | latex_documents = [ 141 | (master_doc, 'Zroya.tex', 'Zroya Documentation', 142 | 'Jan Malčák', 'manual'), 143 | ] 144 | 145 | 146 | # -- Options for manual page output ------------------------------------------ 147 | 148 | # One entry per manual page. List of tuples 149 | # (source start file, name, description, authors, manual section). 150 | man_pages = [ 151 | (master_doc, 'zroya', 'Zroya Documentation', 152 | [author], 1) 153 | ] 154 | 155 | 156 | # -- Options for Texinfo output ---------------------------------------------- 157 | 158 | # Grouping the document tree into Texinfo files. List of tuples 159 | # (source start file, target name, title, author, 160 | # dir menu entry, description, category) 161 | texinfo_documents = [ 162 | (master_doc, 'Zroya', 'Zroya Documentation', 163 | author, 'Zroya', 'One line description of project.', 164 | 'Miscellaneous'), 165 | ] 166 | 167 | 168 | # -- Extension configuration ------------------------------------------------- 169 | 170 | def setup(app): 171 | app.add_stylesheet("css/styles.css") 172 | -------------------------------------------------------------------------------- /docs_source/sphinx/source/content.rst: -------------------------------------------------------------------------------- 1 | Tutorial 2 | ======== 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | 7 | in_action 8 | tutorials/installation 9 | tutorials/index 10 | tutorials/template 11 | tutorials/callbacks 12 | documentation 13 | committing 14 | -------------------------------------------------------------------------------- /docs_source/sphinx/source/documentation.rst: -------------------------------------------------------------------------------- 1 | API Documentation 2 | ================= 3 | 4 | Functions 5 | --------- 6 | .. automodule:: zroya 7 | :members: init, show, hide 8 | 9 | Template 10 | -------- 11 | 12 | .. autoclass:: zroya.Template 13 | :members: 14 | 15 | TemplateType 16 | ^^^^^^^^^^^^ 17 | 18 | .. autoclass:: zroya.TemplateType 19 | :members: 20 | 21 | Audio 22 | ----- 23 | 24 | .. autoclass:: zroya.Audio 25 | :members: 26 | 27 | AudioMode 28 | ^^^^^^^^^ 29 | 30 | .. autoclass:: zroya.AudioMode 31 | :members: 32 | 33 | DismissReason 34 | ------------- 35 | 36 | .. autoclass:: zroya.DismissReason 37 | :members: 38 | -------------------------------------------------------------------------------- /docs_source/sphinx/source/in_action.rst: -------------------------------------------------------------------------------- 1 | In Action 2 | ========= 3 | 4 | This page contains code snippets with summary of zroya's abilities. See :doc:`tutorials/index` for more detailed 5 | introduction. 6 | 7 | Simple Notification 8 | ------------------- 9 | 10 | .. code-block:: python 11 | 12 | import zroya 13 | 14 | zroya.init("Python", "a", "b", "c", "d") 15 | t = zroya.Template(zroya.TemplateType.Text1) 16 | t.setFirstLine("Just one bold line") 17 | zroya.show(t) 18 | 19 | .. figure:: _static/in_action_one_line.png 20 | :alt: Notification with one bold line 21 | 22 | Multiline Notification With Image 23 | --------------------------------- 24 | 25 | .. code-block:: python 26 | 27 | import zroya 28 | 29 | zroya.init("Python", "a", "b", "c", "d") 30 | t = zroya.Template(zroya.TemplateType.ImageAndText4) 31 | t.setFirstLine("First bold line") 32 | t.setSecondLine("Second line is in regular font") 33 | t.setImage("./files/image.png") 34 | zroya.show(t) 35 | 36 | .. figure:: _static/in_action_multiline_image.png 37 | :alt: Notification with one bold, one regular line and an image. 38 | 39 | Attaching callbacks 40 | ------------------- 41 | 42 | .. code-block:: python 43 | 44 | import zroya 45 | import time 46 | 47 | def onClickHandler(notification_id): 48 | print("Clicked!") 49 | 50 | zroya.init("Python", "a", "b", "c", "d") 51 | t = zroya.Template(zroya.TemplateType.Text1) 52 | t.setFirstLine("Click on me, please!") 53 | zroya.show(t, on_click=onClickHandler) 54 | time.sleep(10) 55 | -------------------------------------------------------------------------------- /docs_source/sphinx/source/index.rst: -------------------------------------------------------------------------------- 1 | Welcome to Zroya's documentation! 2 | ================================= 3 | 4 | Zroya is a Python extension which allows you to create native Windows notifications. 5 | 6 | Installation 7 | ------------ 8 | 9 | Zroya is available from pypi: 10 | 11 | .. code-block:: Bash 12 | 13 | python pip install zroya 14 | 15 | Requirements 16 | ------------ 17 | 18 | There are no requirements for zroya at the moment. 19 | 20 | What next? 21 | ---------- 22 | 23 | Are you interested? Visit :doc:`in_action` and decide, if it is the right package for you. If so, I recommend you to 24 | take a look at :doc:`tutorials/index`. 25 | 26 | .. include:: content.rst 27 | 28 | -------------------------------------------------------------------------------- /docs_source/sphinx/source/tutorials/callbacks.rst: -------------------------------------------------------------------------------- 1 | Callbacks 2 | ========= 3 | 4 | In the previous part of the tutorial, action buttons were added. But they did nothing. In this tutorial, 5 | I'll teach you how to make them alive. 6 | 7 | But first I have to introduce you into zroya's callback system. Zroya registers four different events: 8 | 9 | * **onClick** - Fired every time user clicks on notification. 10 | * **onAction** - Activated when action button is clicked. 11 | * **onDismiss** - When the notification is dismissed by user or automatically. 12 | * **onFail** - Something went wrong. 13 | 14 | If you want to be informed, when any of them happens, register event handler with **on_** parameters of 15 | :py:func:`zroya.show`. Event handler is nothing more than a regular function taking one, or two parameters. Number of 16 | parameters depends on the event you register for. 17 | 18 | On Click 19 | --------- 20 | 21 | On click handler takes one parameter and it is notification ID. This is the number you get as a return value from 22 | :py:func:`zroya.show`. 23 | 24 | .. code-block:: python 25 | 26 | def onClickHandler(notification_id): 27 | pass 28 | 29 | On Action 30 | --------- 31 | 32 | On Action handler takes two parameters, notification ID and action ID. Action ID is number returned by 33 | :py:meth:`zroya.Template.addAction`. 34 | 35 | .. code-block:: python 36 | 37 | def onActionHandler(notification_id, action_id): 38 | pass 39 | 40 | On Dismiss 41 | ---------- 42 | 43 | On Dismiss handler is function with two parameters. First one is notification ID. The second one is 44 | :py:class:`zroya.DismissReason`. 45 | 46 | .. code-block:: python 47 | 48 | def onDismissHandler(notification_id, reason): 49 | pass 50 | 51 | On Fail 52 | ------- 53 | 54 | Last, on fail handler is function with one parameter, the same as on click callback. The parameter is notification ID 55 | returned from :py:func:`zroya.show`. 56 | 57 | .. code-block:: python 58 | 59 | def onFailHandler(notification_id): 60 | pass 61 | 62 | Adding handlers 63 | --------------- 64 | 65 | Let's go back a bit. In :doc:`template`, we created a notification for simple bot asking user "How are you?". Now 66 | we add response to each of the action button. 67 | 68 | .. code-block:: python 69 | 70 | import zroya 71 | import time 72 | 73 | # Initialization is required. But in real usage, check the return code, please. 74 | zroya.init("python", "a", "b", "c", "d") 75 | 76 | # Template for question 77 | ask_template = zroya.Template(zroya.TemplateType.ImageAndText4) 78 | ask_template.setFirstLine("Hi, I am NotifyBot.") 79 | ask_template.setSecondLine("It is nice to meet you.") 80 | ask_template.setThirdLine("How are you?") 81 | ask_template.setImage("./files/image.png") 82 | ask_template.addAction("I'm OK, I guess") 83 | ask_template.addAction("Fine") 84 | 85 | # Response for Fine 86 | fine_template = zroya.Template(zroya.TemplateType.Text1) 87 | fine_template.setFirstLine("Glad to hear that!") 88 | 89 | # Response for OK 90 | ok_template = zroya.Template(zroya.TemplateType.Text1) 91 | ok_template.setFirstLine("I'm sorry to hear that!") 92 | 93 | 94 | # prepare handler 95 | def onAction(nid, action_id): 96 | global fine_template, ok_template 97 | 98 | if action_id == 0: 99 | zroya.show(ok_template) 100 | else: 101 | zroya.show(fine_template) 102 | 103 | # Show question 104 | zroya.show(ask_template, on_action=onAction) 105 | 106 | # Keep application running, unless onAction handler is never executed. 107 | time.sleep(10) 108 | 109 | Adding images to answers with emoticons, changing sounds etc. would take this to whole new level. You can always play 110 | with it as you wish. 111 | 112 | I owe you one more answer. How did I know that "I'm OK", gets action ID 0 and "Fine" is ID 1? See 113 | :py:meth:`zroya.Template.addAction` ;) Now enjoy the result: 114 | 115 | .. figure:: ../_static/tutorials_callbacks_final.gif 116 | :alt: Process of asking "How are you" followed with the response on me clicking on "I'm fine". 117 | 118 | Pretty impressive, isn't it? 119 | -------------------------------------------------------------------------------- /docs_source/sphinx/source/tutorials/index.rst: -------------------------------------------------------------------------------- 1 | First steps 2 | =========== 3 | 4 | This tutorial focus only on the basics. It will walk you through setting zroya up, creating template, adding attributes 5 | to it and finally showing a notification. 6 | 7 | Before you follow this tutorial, make sure zroya is installed. See :doc:`installation`. 8 | 9 | .. code-block:: python 10 | 11 | import zroya 12 | 13 | First thing you have to do each time you want to use zroya is to initialize it. This is 14 | required for Windows to associate Python application with notifications. 15 | 16 | .. code-block:: python 17 | 18 | import zroya 19 | 20 | status = zroya.init( 21 | app_name="NotifyBot", 22 | company_name="MyBotCorp", 23 | product_name="NoBo", 24 | sub_product="core", 25 | version="v01" 26 | ) 27 | 28 | if not status: 29 | print("Initialization failed") 30 | 31 | Note that all parameters of :py:func:`zroya.init` are required and they have to be strings. As you see, 32 | :py:func:`zroya.init` returns a boolean status. Always make sure that initialization did not fail. 33 | 34 | Notification templates 35 | ---------------------- 36 | 37 | Now you are ready to create a notification. Each one is based on a :py:class:`zroya.Template`. It holds 38 | all information about the notification - text, image, sounds, etc. 39 | 40 | There are some predefined template types. Think of them as a form you fill blank fields into. The simplest type is 41 | :py:attr:`zroya.TemplateType.Text1`, which have only one field - first line. Filling anything more will result in 42 | errors. 43 | 44 | All types are defined in :py:class:`zroya.TemplateType` class. Select one of them and we will use it to create a 45 | template. 46 | 47 | .. code-block:: python 48 | 49 | # zroya is imported and initialized at this moment 50 | template = zroya.Template(zroya.TemplateType.Text1) 51 | 52 | As you can see, you pass selected template type as a parameter to constructor of :py:class:`zroya.Template`. 53 | 54 | Set it's text 55 | ------------- 56 | 57 | We did create a template. But it does not hold anything. Say you want to show "Hi, how are you?" in it. Following code 58 | will do so: 59 | 60 | .. code-block:: python 61 | 62 | # template is an instance of zroya.Template 63 | template.setFirstLine("Hi, how are you?") 64 | 65 | Show it to the world 66 | -------------------- 67 | 68 | We got there, finally. It is time to show the notification. Use :py:func:`zroya.show` function and pass it **template** 69 | as first parameter: 70 | 71 | .. code-block:: python 72 | 73 | # template is an instance of zroya.Template 74 | zroya.show(template) 75 | 76 | :py:func:`zroya.show` has more parameters, but they don't have to bother you at the moment. We will focus on them in 77 | following steps of this tutorial. 78 | 79 | If everything went right, you should register a notification showing up at the right down corner of your screen. 80 | 81 | .. figure:: ../_static/tutorials_first_steps.png 82 | :alt: Image of notification saying "Hi, how are you?" 83 | 84 | Result of our hard work :) 85 | 86 | Troubleshooting 87 | --------------- 88 | 89 | **Calling** :py:func:`zroya.init` **failed**: This shouldn't happen. Please make sure to `report it`_. It helps me a lot 90 | with debugging and serving you the best product. 91 | 92 | **There is no notification!**: Make sure it is allowed for python (or for any app you are using zroya in) to create 93 | notifications. 94 | 95 | Head to *Settings* **=>** *System* **=>** *Notifications and Actions*. Scroll down and find Python. Set Notifications to 96 | On. 97 | 98 | .. figure:: ../_static/tutorials_first_steps_troubleshooting.gif 99 | :alt: Video showing how to enable notifications for python. 100 | 101 | How to enable notifications. 102 | 103 | .. _report it: https://github.com/malja/zroya/issues/new -------------------------------------------------------------------------------- /docs_source/sphinx/source/tutorials/installation.rst: -------------------------------------------------------------------------------- 1 | Instalation 2 | =========== 3 | 4 | Installing zroya is pretty straight forward. Just use pypi: 5 | 6 | .. code-block:: bash 7 | 8 | python -m pip install zroya 9 | 10 | Installing from source code 11 | --------------------------- 12 | 13 | For building zroya from source code, Visual C++ Libraries have to be installed in the first place. 14 | 15 | Then clone latest version of zroya: 16 | 17 | .. code-block:: bash 18 | 19 | git clone https://github.com/malja/zroya.git 20 | 21 | And build it with distutils: 22 | 23 | .. code-block:: bash 24 | 25 | python setup.py build -------------------------------------------------------------------------------- /docs_source/sphinx/source/tutorials/template.rst: -------------------------------------------------------------------------------- 1 | Further on templates 2 | ==================== 3 | 4 | In previous tutorial, we managed to create a notification from template. In this part, we will make the most from 5 | templates. 6 | 7 | Multiple lines 8 | -------------- 9 | 10 | As I said in previous tutorial, not each :py:class:`zroya.TemplateType` supports multiple lines of text. So make 11 | sure you pick the right one - for example :py:attr:`zroya.TemplateType.ImageAndText4`. You may set up to three lines of 12 | text to it. 13 | 14 | .. code-block:: python 15 | 16 | # zroya is imported and initialized 17 | template = zroya.Template(zroya.TemplateType.ImageAndText4) 18 | template.setFirstLine("Hi, I am NotifyBot.") 19 | template.setSecondLine("It is nice to meet you.") 20 | template.setThirdLine("How are you?") 21 | 22 | zroya.show(template) 23 | 24 | At the moment, zroya supports up to three lines - each one is set by it's own function - 25 | :py:meth:`zroya.Template.setFirstLine`, :py:meth:`zroya.Template.setSecondLine` and 26 | :py:meth:`zroya.Template.setThirdLine`. 27 | 28 | .. figure:: ../_static/tutorials_template_three_lines.png 29 | :alt: Image with a notification which contains three lines of text. First line is bold. 30 | 31 | Notification with three lines of text 32 | 33 | Getting the text back 34 | --------------------- 35 | 36 | Except functions for setting text, there are functions for getting it back from template. They are named 37 | :py:meth:`zroya.Template.getFirstLine`, :py:meth:`zroya.Template.getSecondLine` and 38 | :py:meth:`zroya.Template.getThirdLine` respectively. 39 | 40 | We will use template from previous example to get second line back: 41 | 42 | .. code-block:: python 43 | 44 | print(template.getSecondLine()) 45 | #> "It is nice to meet you." 46 | 47 | If there is no such text, empty string is returned. 48 | 49 | Change sound 50 | ------------ 51 | 52 | It is all nice and so, but the sound Windows does when notification is created is sooo boring, right? Let's change it. 53 | 54 | .. code-block:: python 55 | 56 | template.setAudio(zroya.Audio.Call4) 57 | 58 | Sadly, there is no way to play just any sound you want. You can choose from plenty of sounds defined in 59 | :py:class:`zroya.Audio` class. On the other hand, they are available at any Windows station. 60 | 61 | If this is not enough, you can play selected sound in loop until the notification is moved to Action Center, 62 | or until user dismiss it. 63 | 64 | .. code-block:: python 65 | 66 | template.setAudio(zroya.Audio.Call4, zroya.AudioMode.Looping) 67 | 68 | But I wouldn't recommend it. On the other hand, muting notifications may be usable a bit more: 69 | 70 | .. code-block:: python 71 | 72 | template.setAudio(mode=zroya.AudioMode.Silence) 73 | 74 | Expiration time 75 | --------------- 76 | 77 | Notifications will stay in Action Center until you shut the application off or you manually remove them from there. 78 | But some notifications should have shorter lifespan - for example weather reports. There is no use of the old ones. 79 | Beside hiding them from code, :py:meth:`zroya.Template.setExpiration` comes to aid. 80 | 81 | .. code-block:: python 82 | 83 | template.setExpiration(1000) 84 | 85 | It takes a number of milliseconds after which the notification is automatically removed from Action Center. 86 | 87 | Images 88 | ------ 89 | 90 | UI is key to user's heart. Let's make bot more friendly. Add image with :py:meth:`zroya.Template.setImage`. 91 | 92 | .. code-block:: python 93 | 94 | template.setImage("./image.png") 95 | 96 | .. figure:: ../_static/tutorials_template_image.png 97 | :alt: Notification with friendly image of bot. 98 | 99 | Isn't he cute :* 100 | 101 | At this point, we make use of that :py:attr:`zroya.TemplateType.ImageAndText4` template type. For example 102 | with :py:attr:`zroya.TemplateType.Text4`, this function would return False every time, because it does not support 103 | this type. 104 | 105 | Actions 106 | ------- 107 | 108 | One pretty cool feature is adding actions. Those are buttons which can have attached some action to them. When user 109 | click them, event is fired. See :doc:`callbacks`. 110 | 111 | In this example, we add two buttons to respond question notification is asking. What a wonderful time, answering 112 | your own questions :). 113 | 114 | .. code-block:: python 115 | 116 | template.addAction("I'm OK, I guess") 117 | template.addAction("Fine") 118 | 119 | .. figure:: ../_static/tutorials_template_actions.png 120 | :alt: Notification with buttons for answering the question 121 | 122 | Answer the question, please. 123 | 124 | As you probably noticed, they don't do much now. Just dismiss it. We will do something about it in the next tutorial. 125 | 126 | Troubleshooting 127 | --------------- 128 | 129 | **Actions fail to be added**: Actions are one of Windows 8.1+ features. If you have older system, they won't work. -------------------------------------------------------------------------------- /generate_stubs.py: -------------------------------------------------------------------------------- 1 | import inspect 2 | import sys 3 | 4 | # This script generates zroya stub file from documentation zroya C/C++ code. 5 | # Stub file is a hint for IDE. It contains a list of all functions and methods in zroya with docstrings. 6 | 7 | # TODO: Find better way for output formatting than this 8 | 9 | 10 | def GenerateStubFile(path_to_pyd, path_to_python_files): 11 | 12 | # Add Path to .pyd file with zroya to import path 13 | sys.path.append(path_to_pyd) 14 | sys.path.append(path_to_python_files) 15 | 16 | # Import zroya module 17 | import _zroya 18 | import template_enums 19 | import dismiss_reason 20 | 21 | modules = [ 22 | _zroya, 23 | template_enums, 24 | dismiss_reason 25 | ] 26 | 27 | # Generate .pyi file for zroya module 28 | with open("./zroya/zroya.pyi", "w", encoding="utf8") as output: 29 | 30 | for module in modules: 31 | 32 | # Get all classes/functions in zroya package 33 | for name, obj in inspect.getmembers(module): 34 | 35 | # TODO: Do not expose Enum class at all 36 | if "Enum" in name: 37 | continue 38 | 39 | # Is it a package function 40 | if inspect.isbuiltin(obj): 41 | 42 | # Print def (): 43 | output.write("def {}{}:\n".format(name, inspect.signature(obj))) 44 | # Print functions docstring 45 | output.write("\t\"\"\"\n\t{}\n\t\"\"\"\n\tpass\n\n".format(inspect.getdoc(obj).replace("\n", "\n\t"))) 46 | 47 | # Is it a class 48 | if inspect.isclass(obj): 49 | 50 | # Print class : 51 | output.write("class {}:\n".format(name)) 52 | # Print class docstring 53 | output.write("\t\"\"\"{}\"\"\"\n\n".format(obj.__doc__)) 54 | 55 | # Get all attributes of class 56 | for member_name, member_value in inspect.getmembers(obj): 57 | 58 | # Ignore zroya members 59 | if member_name[0] != "_": 60 | # Is it zroya enum? 61 | if hasattr(member_value, "value"): 62 | member_value = member_value.value 63 | 64 | # Is value string 65 | if isinstance( member_value, str): 66 | # Put " and " around value 67 | output.write("\t{} = \"{}\"\n\n".format(member_name, member_value)) 68 | elif isinstance( member_value, int): 69 | # Print number 70 | output.write("\t{} = {}\n\n".format(member_name, member_value)) 71 | 72 | # Get all methods from class 73 | for cname, cobj in inspect.getmembers(obj): 74 | # Is it a method? Ignoring those starting with undercore, because zroya does not set them. 75 | if inspect.ismethoddescriptor(cobj) and cname[0] != "_": 76 | # Get method signature. Replace leading and trailing bracket, because I have to add self parameter 77 | 78 | signature = str(inspect.signature(cobj)).replace("(", "").replace(")", "") 79 | # Print: def (self, ): 80 | 81 | if len(signature) == 0: 82 | output.write("\tdef {}(self):\n".format(cname)) 83 | else: 84 | output.write("\tdef {}(self, {}):\n".format(cname, signature)) 85 | 86 | # Print methods docstring 87 | output.write("\t\t\"\"\"\n\t\t{}\n\t\t\"\"\"\n\t\tpass\n\n".format(inspect.getdoc(cobj).replace("\n", "\n\t\t"))) -------------------------------------------------------------------------------- /module/event_handler.cpp: -------------------------------------------------------------------------------- 1 | #include "event_handler.h" 2 | 3 | void zroya::EventHandler::toastActivated(INT64 notificationID) const { 4 | std::cout << "Cpp: EventHandler: Activated: " << notificationID << std::endl; 5 | 6 | auto it = this->callbacks.find(notificationID); 7 | if (it != this->callbacks.end()) { 8 | 9 | std::cout << "Cpp: EventHandler: Activated: Event found" << std::endl; 10 | 11 | PyObject *onClicked = it->second->clicked; 12 | 13 | if (onClicked) { 14 | 15 | std::cout << "Cpp: EventHandler: Activated: Event handler is set" << std::endl; 16 | 17 | if (PyCallable_Check(onClicked)) { 18 | 19 | std::cout << "Cpp: EventHandler: Activated: Event handler is callable" << std::endl; 20 | 21 | PyGILState_STATE gstate; 22 | gstate = PyGILState_Ensure(); 23 | 24 | PyObject *args = Py_BuildValue("(L)", notificationID); 25 | 26 | PyObject_CallObject(onClicked, args); 27 | 28 | PyGILState_Release(gstate); 29 | } 30 | } 31 | } 32 | } 33 | 34 | void zroya::EventHandler::toastActivated(int actionIndex, INT64 notificationID) const { 35 | std::cout << "Cpp: EventHandler: Activated2: " << notificationID << std::endl; 36 | 37 | auto it = this->callbacks.find(notificationID); 38 | if (it != this->callbacks.end()) { 39 | 40 | std::cout << "Cpp: EventHandler: Activated2: Event found" << std::endl; 41 | 42 | PyObject *onAction = it->second->action; 43 | 44 | if (onAction) { 45 | 46 | std::cout << "Cpp: EventHandler: Activated2: Event handler is set" << std::endl; 47 | 48 | if (PyCallable_Check(onAction)) { 49 | 50 | std::cout << "Cpp: EventHandler: Activated2: Event handler is callable" << std::endl; 51 | 52 | PyGILState_STATE gstate; 53 | gstate = PyGILState_Ensure(); 54 | 55 | PyObject *args = Py_BuildValue("(L, i)", notificationID, actionIndex); 56 | 57 | PyObject_CallObject(onAction, args); 58 | 59 | PyGILState_Release(gstate); 60 | } 61 | } 62 | } 63 | } 64 | 65 | void zroya::EventHandler::toastDismissed(WinToastLib::IWinToastHandler::WinToastDismissalReason state, INT64 notificationID) const { 66 | std::cout << "Cpp: EventHandler: Dismiss: " << notificationID << std::endl; 67 | 68 | auto it = this->callbacks.find(notificationID); 69 | if (it != this->callbacks.end()) { 70 | 71 | std::cout << "Cpp: EventHandler: Dismiss: Event found" << std::endl; 72 | 73 | PyObject *onDismiss = it->second->dismissed; 74 | 75 | if (onDismiss) { 76 | 77 | std::cout << "Cpp: EventHandler: Dismiss: Event handler is set" << std::endl; 78 | 79 | if (PyCallable_Check(onDismiss)) { 80 | 81 | std::cout << "Cpp: EventHandler: Dismiss: Event handler is callable" << std::endl; 82 | 83 | PyGILState_STATE gstate; 84 | gstate = PyGILState_Ensure(); 85 | 86 | PyObject *zroya_module = PyImport_ImportModule("zroya"); 87 | if (!zroya_module) { 88 | std::cout << "no zroya module" << std::endl; 89 | return; 90 | } 91 | 92 | PyObject *zroya_DissmissReason = PyObject_GetAttrString(zroya_module, "DismissReason"); 93 | if (!zroya_DissmissReason) { 94 | std::cout << "No dismiss reason class" << std::endl; 95 | return; 96 | } 97 | 98 | PyObject* zroya_DismissReason_instance = PyObject_CallFunction(zroya_DissmissReason, "i", (int)state); 99 | PyObject *args = Py_BuildValue("(L, O)", notificationID, zroya_DismissReason_instance); 100 | //PyObject *args = Py_BuildValue("(L, i)", notificationID, (int)state ); 101 | 102 | PyObject_CallObject(onDismiss, args); 103 | 104 | PyGILState_Release(gstate); 105 | } 106 | } 107 | } 108 | } 109 | 110 | void zroya::EventHandler::toastFailed(INT64 notificationID) const { 111 | std::cout << "Cpp: EventHandler: Failed: " << notificationID << std::endl; 112 | 113 | auto it = this->callbacks.find(notificationID); 114 | if (it != this->callbacks.end()) { 115 | 116 | std::cout << "Cpp: EventHandler: Failed: Event found" << std::endl; 117 | 118 | PyObject *onFailed = it->second->failed; 119 | 120 | if (onFailed) { 121 | 122 | std::cout << "Cpp: EventHandler: Failed: Event handler is set" << std::endl; 123 | 124 | if (PyCallable_Check(onFailed)) { 125 | 126 | std::cout << "Cpp: EventHandler: Failed: Event handler is callable" << std::endl; 127 | 128 | PyGILState_STATE gstate; 129 | gstate = PyGILState_Ensure(); 130 | 131 | PyObject *args = Py_BuildValue("(L)", notificationID); 132 | 133 | PyObject_CallObject(onFailed, args); 134 | 135 | PyGILState_Release(gstate); 136 | } 137 | } 138 | } 139 | } 140 | 141 | void zroya::EventHandler::addCallbacks(INT64 notificationID, PyObject *clicked, PyObject *action, PyObject *dismissed, PyObject *failed) { 142 | 143 | this->callbacks.insert( 144 | std::pair( 145 | notificationID, 146 | new Event(clicked, action, dismissed, failed) 147 | ) 148 | ); 149 | } -------------------------------------------------------------------------------- /module/event_handler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "wintoastlib.h" 4 | #include 5 | 6 | namespace zroya { 7 | 8 | /** 9 | * Notification handler. Each of toast* methods is called by WinToastLib when corresponding 10 | * event fires. Event handler get a notification ID and looks if it has registered callback. 11 | * If so, it is called. 12 | */ 13 | class EventHandler : public WinToastLib::IWinToastHandler { 14 | 15 | enum EventType { 16 | Activated, 17 | Action, 18 | Dismissed, 19 | Failed 20 | }; 21 | 22 | class Event { 23 | 24 | public: 25 | PyObject *clicked; 26 | PyObject *action; 27 | PyObject *failed; 28 | PyObject *dismissed; 29 | 30 | Event(PyObject *clicked, PyObject *action, PyObject *dismissed, PyObject *failed) { 31 | this->clicked = clicked; 32 | this->action = action; 33 | this->dismissed = dismissed; 34 | this->failed = failed; 35 | } 36 | 37 | ~Event() { 38 | Py_XDECREF(this->clicked); 39 | Py_XDECREF(this->action); 40 | Py_XDECREF(this->dismissed); 41 | Py_XDECREF(this->failed); 42 | } 43 | 44 | }; 45 | 46 | public: 47 | void toastActivated(INT64 notificationID) const; 48 | void toastActivated(int actionIndex, INT64 notificationID) const; 49 | void toastDismissed(WinToastDismissalReason state, INT64 notificationID) const; 50 | void toastFailed(INT64 notificationID) const; 51 | 52 | void addCallbacks(INT64 notificationID, PyObject *activated, PyObject *action = nullptr, PyObject *dismissed = nullptr, PyObject *failed = nullptr); 53 | 54 | ~EventHandler() { 55 | for (auto it = callbacks.begin(); it != callbacks.end(); it++) { 56 | delete it->second; 57 | } 58 | } 59 | 60 | protected: 61 | 62 | std::map callbacks; 63 | }; 64 | } -------------------------------------------------------------------------------- /module/init.cpp: -------------------------------------------------------------------------------- 1 | #include "wintoastlib.h" 2 | #include "utils.h" 3 | #include "init.h" 4 | 5 | bool zroya::init(const std::string &app_name, const std::string &company_name, const std::string &product_name, const std::string &sub_product, const std::string &version) { 6 | 7 | // Set application name 8 | WinToastLib::WinToast::instance()->setAppName( 9 | convert(app_name) 10 | ); 11 | 12 | // Setup new application ID 13 | WinToastLib::WinToast::instance()->setAppUserModelId( 14 | WinToastLib::WinToast::configureAUMI( 15 | convert(company_name), convert(product_name), convert(sub_product), convert(version) 16 | ) 17 | ); 18 | 19 | // Init WinToast library 20 | if (!WinToastLib::WinToast::instance()->initialize()) { 21 | return false; 22 | } 23 | 24 | return true; 25 | } 26 | 27 | /** 28 | * Initialize library with random strings as company_name, product_name, sub_product and version. This version 29 | * will be called when user does not call init explicitly. 30 | */ 31 | bool zroya::init() { 32 | return zroya::init( 33 | std::string("python"), 34 | random_string(5), 35 | random_string(5), 36 | random_string(5), 37 | random_string(5) 38 | ); 39 | } -------------------------------------------------------------------------------- /module/init.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace zroya { 5 | 6 | /** 7 | * Initialize WinToastLib with provided parameters. 8 | */ 9 | bool init(const std::string &app_name, const std::string &company_name, const std::string &product_name, const std::string &sub_product, const std::string &version); 10 | 11 | /** 12 | * Initialize WinToastLib with random parameters. Used for automatical init when user does not call init function explicitly. 13 | */ 14 | bool init(); 15 | } -------------------------------------------------------------------------------- /module/module.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.27428.2002 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "module", "module\module.vcxproj", "{52FB84A8-EA34-4C64-9E80-84CC1436FB40}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {52FB84A8-EA34-4C64-9E80-84CC1436FB40}.Debug|x64.ActiveCfg = Debug|x64 17 | {52FB84A8-EA34-4C64-9E80-84CC1436FB40}.Debug|x64.Build.0 = Debug|x64 18 | {52FB84A8-EA34-4C64-9E80-84CC1436FB40}.Debug|x86.ActiveCfg = Debug|Win32 19 | {52FB84A8-EA34-4C64-9E80-84CC1436FB40}.Debug|x86.Build.0 = Debug|Win32 20 | {52FB84A8-EA34-4C64-9E80-84CC1436FB40}.Release|x64.ActiveCfg = Release|x64 21 | {52FB84A8-EA34-4C64-9E80-84CC1436FB40}.Release|x64.Build.0 = Release|x64 22 | {52FB84A8-EA34-4C64-9E80-84CC1436FB40}.Release|x86.ActiveCfg = Release|Win32 23 | {52FB84A8-EA34-4C64-9E80-84CC1436FB40}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {CBED5592-BA13-438B-B356-0BB71AEF144C} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /module/module/module.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 15.0 23 | {52FB84A8-EA34-4C64-9E80-84CC1436FB40} 24 | module 25 | 10.0.16299.0 26 | 27 | 28 | 29 | Application 30 | true 31 | v141 32 | MultiByte 33 | 34 | 35 | Application 36 | false 37 | v141 38 | true 39 | MultiByte 40 | 41 | 42 | Application 43 | true 44 | v141 45 | MultiByte 46 | 47 | 48 | Application 49 | false 50 | v141 51 | true 52 | MultiByte 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | C:\Users\janma\AppData\Local\Programs\Python\Python36-32\include;$(IncludePath) 74 | C:\Users\janma\AppData\Local\Programs\Python\Python36-32\Lib;$(LibraryPath) 75 | 76 | 77 | 78 | Level3 79 | Disabled 80 | true 81 | true 82 | 83 | 84 | 85 | 86 | Level3 87 | Disabled 88 | true 89 | true 90 | 91 | 92 | 93 | 94 | Level3 95 | MaxSpeed 96 | true 97 | true 98 | true 99 | true 100 | 101 | 102 | true 103 | true 104 | 105 | 106 | 107 | 108 | Level3 109 | MaxSpeed 110 | true 111 | true 112 | true 113 | true 114 | 115 | 116 | true 117 | true 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | -------------------------------------------------------------------------------- /module/module/module.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {d272300f-f419-40cd-8f71-f1119be73907} 18 | 19 | 20 | {ffb50eb8-b1cc-4703-aeaf-7ebdce10240b} 21 | 22 | 23 | {aada2f26-b8b7-46bf-8a62-6798194d9d2a} 24 | 25 | 26 | {2e5f86c2-90ab-416e-8103-62b3c3011206} 27 | 28 | 29 | 30 | 31 | Hlavičkové soubory 32 | 33 | 34 | Hlavičkové soubory 35 | 36 | 37 | Hlavičkové soubory 38 | 39 | 40 | Hlavičkové soubory\python 41 | 42 | 43 | Hlavičkové soubory\python 44 | 45 | 46 | Hlavičkové soubory\python 47 | 48 | 49 | Hlavičkové soubory\python 50 | 51 | 52 | Hlavičkové soubory\wintoast 53 | 54 | 55 | 56 | 57 | Zdrojové soubory 58 | 59 | 60 | Zdrojové soubory 61 | 62 | 63 | Zdrojové soubory 64 | 65 | 66 | Zdrojové soubory\python 67 | 68 | 69 | Zdrojové soubory\python 70 | 71 | 72 | Zdrojové soubory\python 73 | 74 | 75 | Zdrojové soubory\python 76 | 77 | 78 | Zdrojové soubory\wintoast 79 | 80 | 81 | -------------------------------------------------------------------------------- /module/module/module.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /module/py_init.cpp: -------------------------------------------------------------------------------- 1 | #include "py_init.h" 2 | #include "init.h" 3 | #include "utils.h" 4 | #include "wintoastlib.h" 5 | #include "py_template.h" 6 | #include "event_handler.h" 7 | 8 | #include 9 | 10 | PyObject *zroya_init(PyObject *module, PyObject *args, PyObject *kwargs) { 11 | 12 | // List of all parameters this function may get 13 | static char *keywords[] = { (char*)"app_name", (char*)"company_name", (char*)"product_name", (char*)"sub_product", (char*)"version", nullptr }; 14 | 15 | const char* app_name, *company_name, *product_name, *sub_product, *version; 16 | 17 | // Parse arguments 18 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sssss", keywords, &app_name, &company_name, &product_name, &sub_product, &version)) { 19 | PyErr_SetString(PyExc_ValueError, "all parameters must be string"); 20 | return nullptr; 21 | } 22 | 23 | if (strlen(app_name) == 0 || 24 | strlen(company_name) == 0 || 25 | strlen(product_name) == 0 || 26 | strlen(sub_product) == 0 || 27 | strlen(version) == 0) { 28 | PyErr_SetString(PyExc_ValueError, "empty parameters are not allowed"); 29 | return nullptr; 30 | } 31 | 32 | // Initialize underlying library with provided parameters. 33 | bool retcode = zroya::init( 34 | std::string(app_name), 35 | std::string(company_name), 36 | std::string(product_name), 37 | std::string(sub_product), 38 | std::string(version) 39 | ); 40 | 41 | if (retcode) { 42 | Py_INCREF(Py_True); 43 | return Py_True; 44 | } 45 | else { 46 | Py_INCREF(Py_False); 47 | return Py_False; 48 | } 49 | 50 | } 51 | 52 | PyObject *zroya_show(PyObject *module, PyObject *args, PyObject *kwargs) { 53 | 54 | // List of all parameters thsi function accept 55 | static char *keywords[] = { (char*)"template", (char*)"on_click", (char*)"on_action", (char*)"on_dismiss", (char*)"on_fail", nullptr }; 56 | 57 | PyObject *toast = nullptr, *on_click = nullptr, *on_action = nullptr, *on_dismiss = nullptr, *on_fail = nullptr; 58 | 59 | // Parse arguments 60 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OOOO", keywords, &toast, &on_click, &on_action, &on_dismiss, &on_fail)) { 61 | return nullptr; 62 | } 63 | 64 | // Make sure template parameter is of zroya.Template type 65 | if (strcmp(toast->ob_type->tp_name, "zroya.Template") != 0) { 66 | PyErr_SetString(PyExc_ValueError, "first parameter must be of zroya.Template type."); 67 | return nullptr; 68 | } 69 | 70 | // Make sure WinToastLib is initialized 71 | if (!WinToastLib::WinToast::instance()->isInitialized()) { 72 | if (!zroya::init()) { 73 | PyErr_SetString(PyExc_SystemError, "initialization failed"); 74 | return nullptr; 75 | } 76 | } 77 | 78 | zroya_State *state = static_cast(PyModule_GetState(module)); 79 | 80 | // Try to show notification and save its ID 81 | INT64 notificationID = WinToastLib::WinToast::instance()->showToast(*(((zroya_Template*)toast)->_template), static_cast(PyModule_GetState(module))->_handler ); 82 | 83 | if (notificationID > 0) { 84 | Py_XINCREF(on_click); 85 | Py_XINCREF(on_action); 86 | Py_XINCREF(on_dismiss); 87 | Py_XINCREF(on_fail); 88 | 89 | state->_handler->addCallbacks(notificationID, on_click, on_action, on_dismiss, on_fail); 90 | } 91 | 92 | return PyLong_FromLongLong(notificationID); 93 | } 94 | 95 | PyObject *zroya_hide(PyObject *module, PyObject *arg, PyObject *kwarg) { 96 | 97 | static char *keywords[] = { (char*)"nid" }; 98 | 99 | PyObject *notificationID = nullptr; 100 | 101 | if (!PyArg_ParseTupleAndKeywords(arg, kwarg, "O", keywords, ¬ificationID )) { 102 | return nullptr; 103 | } 104 | 105 | 106 | /* 107 | // Parse arguments 108 | if (!PyTuple_Check(arg)) { 109 | PyErr_SetString(PyExc_TypeError, "function takes tuple as parameter."); 110 | return nullptr; 111 | } 112 | 113 | // Exactly one parameter is required 114 | if (PyTuple_Size(arg) != 1) { 115 | PyErr_SetString(PyExc_ValueError, "function requires only one parameter."); 116 | return nullptr; 117 | }*/ 118 | 119 | INT64 nID = -1; 120 | 121 | /* 122 | // Get number from PyObject representing tuple 123 | PyObject *tuple = PyTuple_GetItem(arg, 0); 124 | notificationID = PyLong_AsLongLong(tuple); 125 | */ 126 | 127 | // Check if parameter is integer 128 | if (!PyLong_Check(notificationID)) { 129 | PyErr_SetString(PyExc_ValueError, "nid parameter is required to be an integer."); 130 | return nullptr; 131 | } 132 | 133 | // Get notification ID as integer 134 | nID = PyLong_AsLongLong(notificationID); 135 | 136 | // Ignore unvalid values 137 | if (nID < 0) { 138 | PyErr_SetString(PyExc_ValueError, "nid may not be negative."); 139 | return nullptr; 140 | } 141 | 142 | if (WinToastLib::WinToast::instance()->hideToast(nID)) { 143 | Py_INCREF(Py_True); 144 | return Py_True; 145 | } else { 146 | Py_INCREF(Py_False); 147 | return Py_False; 148 | } 149 | 150 | 151 | } 152 | -------------------------------------------------------------------------------- /module/py_init.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "wintoastlib.h" 4 | #include "event_handler.h" 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | /** 11 | * This file defines few core functions required for zroya module. 12 | */ 13 | 14 | /// Zroya global state 15 | typedef struct { 16 | /// Underhood library for notifications 17 | WinToastLib::WinToast *_win_toast; 18 | /// My custom event handler 19 | zroya::EventHandler *_handler; 20 | } zroya_State; 21 | 22 | PyDoc_STRVAR(zroya_init__doc__, 23 | "init(app_name, company_name, product_name, sub_product, version)\n" 24 | "--\n\n" 25 | "Initialize Zroya module. \n" 26 | "\n" 27 | "**Note**: You should call this function before any other manipulation with this module. \n" 28 | "If you do not call this function explicitely, randomly generated strings will be used as default parameters. \n" 29 | "\n" 30 | "Args: \n" 31 | "\tapp_name (str): Application name. \n\n" 32 | "\tcompany_name (str): Part of unique ID created for this application. \n\n" 33 | "\tproduct_name (str): Part of unique ID created for this application. \n\n" 34 | "\tsub_product (str): Part of unique ID created for this application. \n\n" 35 | "\tstr version (str): Part of unique ID created for this application. \n\n" 36 | "\n" 37 | "Returns: \n" 38 | "\tbool: True if initialization is completed, False otherwise." 39 | ); 40 | PyObject *zroya_init(PyObject *self, PyObject *args, PyObject *kwargs); 41 | 42 | PyDoc_STRVAR(zroya_show__doc__, 43 | "show(template, on_click=None, on_action=None, on_dismiss=None, on_fail=None)\n" 44 | "--\n\n" 45 | "Create instance of notification template and show it. If any of on_* parameter is set, corresponding event is registered. See :doc:`tutorials/callbacks`.\n" 46 | "\n" 47 | "Args: \n" 48 | "\ttemplate (:py:class:`zroya.Template`): Template instance. \n\n" 49 | "\ton_click (callable): Callback for onClick event. Occurs when user activates a toast notification through a click or touch. \n\n" 50 | "\ton_action (callable): Callback for onAction event. Occurs when user click on action button. \n\n" 51 | "\ton_dismiss (callable): Callback for onDismiss event. Occurs when the notification leaves the screen, either by expiring or being explicitly dismissed by the user. \n\n" 52 | "\ton_fail (callable): Callback for onFail event. Occurs when an error is caused when Windows attempts to raise a toast notification. \n\n" 53 | "\n" 54 | "Returns: \n" 55 | "\tbool: Notification ID if notification was shown. False otherwise." 56 | ); 57 | PyObject *zroya_show(PyObject *module, PyObject *args, PyObject *kwargs); 58 | 59 | PyDoc_STRVAR(zroya_hide__doc__, 60 | "hide(nid)\n" 61 | "--\n\n" 62 | "Hide notification by ID. This will trigger onDismiss event.\n" 63 | "\n" 64 | "Args: \n" 65 | "\tnid (int): Notification ID obtained from :py:func:`zroya.show` function. \n" 66 | "\n" 67 | "Returns: \n" 68 | "\tbool: True if notification was hidden, false otherwise." 69 | ); 70 | PyObject *zroya_hide(PyObject *module, PyObject *arg, PyObject *kwarg); 71 | 72 | #ifdef __cplusplus 73 | } 74 | #endif -------------------------------------------------------------------------------- /module/py_module.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "py_module.h" 4 | #include "wintoastlib.h" 5 | 6 | /// Clear zroya module 7 | int zroya_clear(PyObject *self) { 8 | zroya_State* state = static_cast(PyModule_GetState(self)); 9 | 10 | // Free 11 | state->_win_toast = nullptr; 12 | delete state->_handler; 13 | 14 | return 0; 15 | } 16 | 17 | /// List of all module functions. 18 | struct PyMethodDef zroya_module_functions[] = { 19 | { "init", (PyCFunction)zroya_init, METH_VARARGS | METH_KEYWORDS, zroya_init__doc__ }, 20 | { "show", (PyCFunction)zroya_show, METH_VARARGS | METH_KEYWORDS, zroya_show__doc__ }, 21 | { "hide", (PyCFunction)zroya_hide, METH_VARARGS | METH_KEYWORDS, zroya_hide__doc__ }, 22 | { nullptr, nullptr, 0, nullptr } 23 | }; 24 | 25 | /// Module definition 26 | struct PyModuleDef zroya_module_definition = { 27 | PyModuleDef_HEAD_INIT, /* Always start definition with this :) */ 28 | "zroya", /* Module name */ 29 | zroya__doc__, /*DOCSTRING*/ 30 | sizeof(zroya_State), /* Set module state as global. */ 31 | zroya_module_functions, /* Module functions */ 32 | nullptr, /* Slots for multi-phase initialization */ 33 | nullptr, /* travelsal function */ 34 | zroya_clear, /* Clean function */ 35 | nullptr /* Free function */ 36 | }; 37 | 38 | /// Module entry point. 39 | PyMODINIT_FUNC PyInit__zroya() { 40 | 41 | // Check if there is zroya module configuration 42 | if (PyType_Ready(&zroya_template_type) < 0) { 43 | return nullptr; 44 | } 45 | 46 | // Create new module named zroya 47 | PyObject *module = PyModule_Create(&zroya_module_definition); 48 | if (!module) { 49 | return nullptr; 50 | } 51 | 52 | // Add Template class to zroya module 53 | if (PyModule_AddObject(module, "Template", (PyObject*)&zroya_template_type) < 0) { 54 | return nullptr; 55 | } 56 | 57 | PyObject *template_dict = zroya_template_type.tp_dict; 58 | 59 | // WinToast singleton should be accessible from anywhere, but keeping instance 60 | // should prevent from unwanted destroying. 61 | zroya_State *state = (zroya_State*)PyModule_GetState(module); 62 | state->_win_toast = WinToastLib::WinToast::instance(); 63 | state->_handler = new zroya::EventHandler; 64 | 65 | if (!PyEval_ThreadsInitialized()) { 66 | PyEval_InitThreads(); 67 | } 68 | 69 | return module; 70 | } 71 | -------------------------------------------------------------------------------- /module/py_module.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "py_init.h" 4 | #include "py_template.h" 5 | #include "event_handler.h" 6 | #include "py_utils.h" 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | /** 13 | * This file sets a new python module - zroya. Coresponding Cpp file contains module 14 | * entry point and all required function for creation and destruction of this module. 15 | */ 16 | 17 | PyDoc_STRVAR(zroya__doc__, 18 | "zroya\n" 19 | "--\n\n" 20 | "Library for creating native Windows 8, Window 9 and Windows 10 notifications. \n" 21 | ); 22 | 23 | #ifdef __cplusplus 24 | } 25 | #endif -------------------------------------------------------------------------------- /module/py_utils.cpp: -------------------------------------------------------------------------------- 1 | #include "py_utils.h" 2 | 3 | bool file_exists(PyObject *file_name) { 4 | 5 | Py_XINCREF(file_name); 6 | 7 | PyObject *import_name = PyUnicode_FromString("os.path"); 8 | 9 | if (!import_name) { 10 | 11 | Py_XDECREF(file_name); 12 | return false; 13 | } 14 | 15 | PyObject *module = PyImport_Import(import_name); 16 | 17 | if (!module) { 18 | 19 | Py_XDECREF(file_name); 20 | Py_XDECREF(import_name); 21 | return false; 22 | } 23 | 24 | PyObject *path_isfile = PyObject_GetAttrString(module, "isfile"); 25 | if (!path_isfile) { 26 | 27 | Py_XDECREF(file_name); 28 | Py_XDECREF(import_name); 29 | Py_XDECREF(module); 30 | return false; 31 | } 32 | 33 | PyObject *arguments = PyTuple_Pack(1, file_name); 34 | 35 | if (!arguments) { 36 | Py_XDECREF(file_name); 37 | Py_XDECREF(import_name); 38 | Py_XDECREF(module); 39 | Py_XDECREF(path_isfile); 40 | return false; 41 | } 42 | 43 | PyObject *ret_val = PyObject_CallObject(path_isfile, arguments); 44 | if (!ret_val) { 45 | Py_XDECREF(file_name); 46 | Py_XDECREF(import_name); 47 | Py_XDECREF(module); 48 | Py_XDECREF(path_isfile); 49 | Py_XDECREF(arguments); 50 | return false; 51 | } 52 | 53 | int result = PyObject_IsTrue(ret_val); 54 | 55 | // Clean up 56 | Py_XDECREF(file_name); 57 | Py_XDECREF(import_name); 58 | Py_XDECREF(module); 59 | Py_XDECREF(path_isfile); 60 | Py_XDECREF(arguments); 61 | Py_XDECREF(ret_val); 62 | 63 | return result == 1; 64 | } 65 | 66 | PyObject *abspath(PyObject *relpath) { 67 | Py_XINCREF(relpath); 68 | 69 | PyObject *import_name = PyUnicode_FromString("os.path"); 70 | 71 | if (!import_name) { 72 | Py_XDECREF(relpath); 73 | 74 | Py_XINCREF(Py_False); 75 | return Py_False; 76 | } 77 | 78 | PyObject *module = PyImport_Import(import_name); 79 | 80 | if (!module) { 81 | Py_XDECREF(relpath); 82 | Py_XDECREF(import_name); 83 | 84 | Py_XINCREF(Py_False); 85 | return Py_False; 86 | } 87 | 88 | PyObject *path_abspath = PyObject_GetAttrString(module, "abspath"); 89 | if (!path_abspath) { 90 | Py_XDECREF(relpath); 91 | Py_XDECREF(import_name); 92 | Py_XDECREF(module); 93 | 94 | Py_XINCREF(Py_False); 95 | return Py_False; 96 | } 97 | 98 | PyObject *arguments = PyTuple_Pack(1, relpath); 99 | 100 | if (!arguments) { 101 | Py_XDECREF(relpath); 102 | Py_XDECREF(import_name); 103 | Py_XDECREF(module); 104 | Py_XDECREF(path_abspath); 105 | 106 | Py_XINCREF(Py_False); 107 | return Py_False; 108 | } 109 | 110 | PyObject *ret_obj = PyObject_CallObject(path_abspath, arguments); 111 | if (!ret_obj) { 112 | Py_XDECREF(relpath); 113 | Py_XDECREF(import_name); 114 | Py_XDECREF(module); 115 | Py_XDECREF(path_abspath); 116 | Py_XDECREF(arguments); 117 | 118 | Py_XINCREF(Py_False); 119 | return false; 120 | } 121 | 122 | // Clean up 123 | Py_XDECREF(relpath); 124 | Py_XDECREF(import_name); 125 | Py_XDECREF(module); 126 | Py_XDECREF(path_abspath); 127 | Py_XDECREF(arguments); 128 | 129 | return ret_obj; 130 | } -------------------------------------------------------------------------------- /module/py_utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | /** 10 | * File with some utilities for zroya module. 11 | */ 12 | 13 | /// Call python os.path.isfile to ensure file 'file_name' exists. 14 | bool file_exists(PyObject *file_name); 15 | 16 | /// Call Python function os.path.abspath to get absolute path from 'relpath'. 17 | /// Returns Py_False on error. 18 | PyObject *abspath(PyObject *relpath); 19 | 20 | #ifdef __cplusplus 21 | } 22 | #endif -------------------------------------------------------------------------------- /module/utils.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "utils.h" 7 | 8 | std::wstring zroya::convert(const char* text) { 9 | static std::wstring_convert> converter; 10 | return std::wstring(converter.from_bytes(text)); 11 | } 12 | 13 | std::wstring zroya::convert(const std::string &text) { 14 | std::wostringstream convert; 15 | convert << text.c_str(); 16 | return std::wstring(convert.str()); 17 | } 18 | 19 | std::string zroya::random_string(int max_length) { 20 | 21 | std::string possible_characters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 22 | std::random_device rd; 23 | std::mt19937 engine(rd()); 24 | std::uniform_int_distribution<> dist(0, possible_characters.size() - 1); 25 | std::string ret = ""; 26 | 27 | for (int i = 0; i < max_length; i++) { 28 | int random_index = dist(engine); //get index between 0 and possible_characters.size()-1 29 | ret += possible_characters[random_index]; 30 | } 31 | 32 | return ret; 33 | } -------------------------------------------------------------------------------- /module/utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace zroya { 5 | 6 | /** 7 | * Convert const char* to std::wstring. 8 | */ 9 | std::wstring convert(const char* text); 10 | 11 | /** 12 | * Convert std::string to std::wstring. 13 | */ 14 | std::wstring convert(const std::string &text); 15 | 16 | /** 17 | * Generate random string of selected length. 18 | */ 19 | std::string random_string(int max_length); 20 | 21 | } -------------------------------------------------------------------------------- /module/wintoastlib.h: -------------------------------------------------------------------------------- 1 | #ifndef WINTOASTLIB_H 2 | #define WINTOASTLIB_H 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | using namespace Microsoft::WRL; 22 | using namespace ABI::Windows::Data::Xml::Dom; 23 | using namespace ABI::Windows::Foundation; 24 | using namespace ABI::Windows::UI::Notifications; 25 | using namespace Windows::Foundation; 26 | 27 | #define DEFAULT_SHELL_LINKS_PATH L"\\Microsoft\\Windows\\Start Menu\\Programs\\" 28 | #define DEFAULT_LINK_FORMAT L".lnk" 29 | namespace WinToastLib { 30 | 31 | class IWinToastHandler { 32 | public: 33 | enum WinToastDismissalReason { 34 | UserCanceled = ToastDismissalReason::ToastDismissalReason_UserCanceled, 35 | ApplicationHidden = ToastDismissalReason::ToastDismissalReason_ApplicationHidden, 36 | TimedOut = ToastDismissalReason::ToastDismissalReason_TimedOut 37 | }; 38 | virtual void toastActivated(INT64 notificationID) const = 0; 39 | virtual void toastActivated(int actionIndex, INT64 notificationID) const = 0; 40 | virtual void toastDismissed(WinToastDismissalReason state, INT64 notificationID) const = 0; 41 | virtual void toastFailed(INT64 notificationID) const = 0; 42 | }; 43 | 44 | class WinToastTemplate { 45 | public: 46 | enum AudioOption { Default = 0, Silent = 1, Loop = 2 }; 47 | enum TextField { FirstLine = 0, SecondLine, ThirdLine }; 48 | enum WinToastTemplateType { 49 | ImageAndText01 = ToastTemplateType::ToastTemplateType_ToastImageAndText01, 50 | ImageAndText02 = ToastTemplateType::ToastTemplateType_ToastImageAndText02, 51 | ImageAndText03 = ToastTemplateType::ToastTemplateType_ToastImageAndText03, 52 | ImageAndText04 = ToastTemplateType::ToastTemplateType_ToastImageAndText04, 53 | Text01 = ToastTemplateType::ToastTemplateType_ToastText01, 54 | Text02 = ToastTemplateType::ToastTemplateType_ToastText02, 55 | Text03 = ToastTemplateType::ToastTemplateType_ToastText03, 56 | Text04 = ToastTemplateType::ToastTemplateType_ToastText04, 57 | WinToastTemplateTypeCount 58 | }; 59 | 60 | WinToastTemplate(_In_ WinToastTemplateType type = ImageAndText02); 61 | ~WinToastTemplate(); 62 | 63 | void setTextField(_In_ const std::wstring& txt, _In_ TextField pos); 64 | void setImagePath(_In_ const std::wstring& imgPath); 65 | void setAudioPath(_In_ const std::wstring& audioPath); 66 | void setAudioOption(_In_ const WinToastTemplate::AudioOption& audioOption); 67 | void setAttributionText(_In_ const std::wstring & attributionText); 68 | void addAction(_In_ const std::wstring& label); 69 | inline void setExpiration(_In_ INT64 millisecondsFromNow) { _expiration = millisecondsFromNow; } 70 | inline int textFieldsCount() const { return static_cast(_textFields.size()); } 71 | inline int actionsCount() const { return static_cast(_actions.size()); } 72 | inline bool hasImage() const { return _type < Text01; } 73 | inline std::vector textFields() const { return _textFields; } 74 | inline std::wstring textField(_In_ TextField pos) const { return _textFields[pos]; } 75 | inline std::wstring actionLabel(_In_ int pos) const { return _actions[pos]; } 76 | inline std::wstring imagePath() const { return _imagePath; } 77 | inline std::wstring audioPath() const { return _audioPath; } 78 | inline std::wstring attributionText() const { return _attributionText; } 79 | inline INT64 expiration() const { return _expiration; } 80 | inline WinToastTemplateType type() const { return _type; } 81 | inline WinToastTemplate::AudioOption audioOption() const { return _audioOption; } 82 | 83 | private: 84 | std::vector _textFields; 85 | std::wstring _imagePath; 86 | std::wstring _audioPath; 87 | std::vector _actions; 88 | INT64 _expiration; 89 | WinToastTemplateType _type; 90 | WinToastTemplate::AudioOption _audioOption = WinToastTemplate::AudioOption::Default; 91 | std::wstring _attributionText; 92 | }; 93 | 94 | class WinToast { 95 | public: 96 | WinToast(void); 97 | virtual ~WinToast(); 98 | static WinToast* instance(); 99 | static bool isCompatible(); 100 | static bool supportModernFeatures(); 101 | static std::wstring configureAUMI(_In_ const std::wstring& companyName, 102 | _In_ const std::wstring& productName, 103 | _In_ const std::wstring& subProduct = std::wstring(), 104 | _In_ const std::wstring& versionInformation = std::wstring() 105 | ); 106 | virtual bool initialize(); 107 | virtual bool isInitialized() const { return _isInitialized; } 108 | virtual INT64 showToast(_In_ const WinToastTemplate& toast, _In_ IWinToastHandler* handler); 109 | virtual bool hideToast(_In_ INT64 id); 110 | virtual void clear(); 111 | inline std::wstring appName() const { return _appName; } 112 | inline std::wstring appUserModelId() const { return _aumi; } 113 | void setAppUserModelId(_In_ const std::wstring& appName); 114 | void setAppName(_In_ const std::wstring& appName); 115 | 116 | enum ShortcutResult { 117 | SHORTCUT_UNCHANGED = 0, 118 | SHORTCUT_WAS_CHANGED = 1, 119 | SHORTCUT_WAS_CREATED = 2, 120 | 121 | SHORTCUT_MISSING_PARAMETERS = -1, 122 | SHORTCUT_INCOMPATIBLE_OS = -2, 123 | SHORTCUT_COM_INIT_FAILURE = -3, 124 | SHORTCUT_CREATE_FAILED = -4 125 | }; 126 | virtual enum ShortcutResult createShortcut(); 127 | protected: 128 | bool _isInitialized; 129 | bool _hasCoInitialized; 130 | std::wstring _appName; 131 | std::wstring _aumi; 132 | std::map> _buffer; 133 | 134 | HRESULT validateShellLinkHelper(_Out_ bool& wasChanged); 135 | HRESULT createShellLinkHelper(); 136 | HRESULT setImageFieldHelper(_In_ IXmlDocument *xml, _In_ const std::wstring& path); 137 | HRESULT setAudioFieldHelper(_In_ IXmlDocument *xml, _In_ const std::wstring& path, _In_opt_ WinToastTemplate::AudioOption option = WinToastTemplate::AudioOption::Default); 138 | HRESULT setTextFieldHelper(_In_ IXmlDocument *xml, _In_ const std::wstring& text, _In_ int pos); 139 | HRESULT setAttributionTextFieldHelper(_In_ IXmlDocument *xml, _In_ const std::wstring& text); 140 | HRESULT addActionHelper(_In_ IXmlDocument *xml, _In_ const std::wstring& action, _In_ const std::wstring& arguments); 141 | ComPtr notifier(_In_ bool* succeded) const; 142 | }; 143 | } 144 | #endif // WINTOASTLIB_H 145 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from shutil import rmtree 4 | from setuptools import setup, Extension, Command 5 | from setuptools.command.test import test 6 | from setuptools.command.build_ext import build_ext 7 | import generate_stubs 8 | import os 9 | import sys 10 | 11 | sys.path.append(os.path.abspath("./zroya/")) 12 | 13 | import version 14 | 15 | here = os.path.abspath(os.path.dirname(__file__)) 16 | 17 | # Include path for _zroya module 18 | includes_list = ["./module"] 19 | 20 | # List of all *.cpp files in ./module directory 21 | sources_list = [] 22 | for root, dirs, files in os.walk("./module"): 23 | for f in files: 24 | if os.path.splitext(f)[1] == ".cpp": 25 | sources_list.append(os.path.join(root, f)) 26 | 27 | # Python C/CPP Api extension configuration 28 | ext_modules = [ 29 | Extension("_zroya", 30 | sources=sources_list, 31 | include_dirs=includes_list 32 | ) 33 | ] 34 | 35 | 36 | def discover_and_run_tests(): 37 | import unittest 38 | 39 | # use the default shared TestLoader instance 40 | test_loader = unittest.defaultTestLoader 41 | 42 | # use the basic test runner that outputs to sys.stderr 43 | test_runner = unittest.TextTestRunner() 44 | 45 | # automatically discover all tests 46 | # NOTE: only works for python 2.7 and later 47 | test_suite = test_loader.discover( os.path.join(here, "tests")) 48 | 49 | # run the test suite 50 | test_runner.run(test_suite) 51 | 52 | 53 | def find_pyd_file(): 54 | """ 55 | Return path to .pyd after successful build command. 56 | :return: Path to .pyd file or None. 57 | """ 58 | 59 | if not os.path.isdir("./build"): 60 | raise NotADirectoryError 61 | 62 | for path, dirs, files in os.walk("./build"): 63 | for file_name in files: 64 | file_name_parts = os.path.splitext(file_name) 65 | if file_name_parts[1] == ".pyd": 66 | return path 67 | return None 68 | 69 | 70 | class StubsCommand(build_ext): 71 | 72 | description = "Generate python stubs with documentation from C code." 73 | 74 | def run(self): 75 | build_ext.run(self) 76 | 77 | print("running stubs") 78 | # Generate .pyd file for this module 79 | generate_stubs.GenerateStubFile(find_pyd_file(), os.path.abspath("./zroya/")) 80 | 81 | 82 | class DocumentationCommand(Command): 83 | 84 | description = "Generate documentation from /docs_source directory." 85 | user_options = [] 86 | 87 | def initialize_options(self): 88 | pass 89 | 90 | def finalize_options(self): 91 | pass 92 | 93 | def run(self): 94 | os.system("{} {}".format(os.path.join(os.path.abspath("./docs_source/sphinx/"), "make.bat"), "html")) 95 | sys.exit() 96 | 97 | 98 | class UploadCommand(Command): 99 | 100 | description = 'Build and publish the package.' 101 | user_options = [ 102 | ( 103 | "pypi=", 104 | "p", 105 | "Set PyPi repository in which should be distribution uploaded. Valid values are 'test' for TestPyPi or \ 106 | 'standard' for regular PyPi." 107 | ) 108 | ] 109 | 110 | @staticmethod 111 | def status(s): 112 | """Prints things in bold.""" 113 | print('\033[1m{0}\033[0m'.format(s)) 114 | 115 | def initialize_options(self): 116 | self.pypi = "standard" 117 | 118 | def finalize_options(self): 119 | assert(self.pypi == "standard" or self.pypi == "test") 120 | 121 | def run(self): 122 | try: 123 | self.status('Removing previous builds…') 124 | rmtree(os.path.join(here, 'dist')) 125 | except OSError: 126 | pass 127 | 128 | self.status('Building Source and Wheel (universal) distribution…') 129 | os.system('{0} setup.py sdist bdist_wheel --universal'.format(sys.executable)) 130 | 131 | self.status('Uploading the package to PyPi via Twine…') 132 | 133 | if self.pypi == "standard": 134 | os.system('twine upload --repository pypi dist/*') 135 | else: 136 | os.system('twine upload --repository testpypi dist/*') 137 | 138 | sys.exit() 139 | 140 | 141 | class DiscoverTest(test): 142 | """ 143 | Discover and run tests. 144 | See: https://stackoverflow.com/questions/17001010/how-to-run-unittest-discover-from-python-setup-py-test 145 | """ 146 | 147 | description = "Run tests in /tests folder with unittest." 148 | 149 | def finalize_options(self): 150 | test.finalize_options(self) 151 | self.test_args = [] 152 | self.test_suite = True 153 | 154 | def run_tests(self): 155 | discover_and_run_tests() 156 | 157 | 158 | setup(name='zroya', 159 | version=version.__version__, 160 | description='Python library for creating native Windows notifications.', 161 | long_description=open("README.md").read(), 162 | 163 | author='Jan Malčák', 164 | author_email='looorin@gmail.com', 165 | 166 | license='MIT', 167 | url='https://malja.github.io/zroya', 168 | 169 | keywords=["notifications", "windows", "toast"], 170 | classifiers=[ 171 | "Development Status :: 4 - Beta", 172 | "Environment :: Win32 (MS Windows)", 173 | "License :: OSI Approved :: MIT License", 174 | "Operating System :: Microsoft :: Windows", 175 | "Programming Language :: C", 176 | "Programming Language :: C++", 177 | "Programming Language :: Python :: 3", 178 | "Topic :: Software Development :: User Interfaces" 179 | ], 180 | 181 | ext_modules=ext_modules, 182 | test_suite="tests", 183 | packages=["zroya"], 184 | cmdclass={ 185 | "stubs": StubsCommand, 186 | 'upload': UploadCommand, 187 | "docs": DocumentationCommand, 188 | "test": DiscoverTest, 189 | } 190 | ) 191 | -------------------------------------------------------------------------------- /tests/files/Readme.txt: -------------------------------------------------------------------------------- 1 | Follows list of all used files and link to their author. Thank you for sharing them ;) 2 | 3 | https://www.iconfinder.com/iconsets/essential-app-2 4 | - image.png 5 | -------------------------------------------------------------------------------- /tests/files/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/malja/zroya/41830133a54528e9cd9ef43d9637a576ac849c11/tests/files/image.png -------------------------------------------------------------------------------- /tests/test_actions.py: -------------------------------------------------------------------------------- 1 | import zroya 2 | import time 3 | import unittest 4 | 5 | 6 | def action_handler(notification_index, action_index): 7 | """ 8 | This is a callback function for onAction event. It is called when user clicks on an action button attached to the 9 | notification. 10 | 11 | :param notification_index: Index of notification in which event occurred. 12 | :param action_index: Index of clicked action. Indexes start from zero (first action) and increase as you add more 13 | actions. 14 | """ 15 | 16 | print("Notification with ID={} was activated. User clicked on action with index={}.".format( 17 | notification_index, action_index 18 | )) 19 | 20 | 21 | class TestTemplateActions(unittest.TestCase): 22 | 23 | def test_basic_action_handler(self): 24 | 25 | # Make sure zroya is initialized 26 | status = zroya.init(app_name="a", company_name="b", product_name="c", sub_product="d", version="e") 27 | 28 | self.assertTrue(status) 29 | 30 | # Create a template with two lines of text 31 | template = zroya.Template(zroya.TemplateType.Text1) 32 | 33 | self.assertIsInstance(template, zroya.Template) 34 | 35 | # Add text to it 36 | template.setFirstLine("My first line is there") 37 | template.setSecondLine("My second line is super catchy.") 38 | 39 | # Add actions 40 | first_action_index = template.addAction("Click me!") 41 | second_action_index = template.addAction("Don't click me!") 42 | 43 | self.assertEqual(first_action_index, 0) 44 | self.assertEqual(second_action_index, 1) 45 | 46 | print("Index first index={}, second index={}".format(first_action_index, second_action_index)) 47 | 48 | # Create a notification with on_action callback attached. 49 | status = zroya.show(template, on_action=action_handler) 50 | 51 | self.assertTrue(status) 52 | 53 | # Make sure application runs for a while 54 | time.sleep(5) 55 | 56 | if __name__ == "__main__": 57 | unittest.main() 58 | -------------------------------------------------------------------------------- /tests/test_callbacks.py: -------------------------------------------------------------------------------- 1 | import zroya 2 | import time 3 | 4 | def onclick(data): 5 | print("Onclick event zroya handler {}".format(data)) 6 | 7 | def ondismiss(data, reason): 8 | print("Dismiss event zroya handler {}, reason {}".format(data, reason)) 9 | print(reason == zroya.DismissReason.User) 10 | 11 | zroya.init("zroya", "a", "b", "c", "d") 12 | 13 | t = zroya.Template(zroya.TemplateType.Text1) 14 | t.setFirstLine("Ahoj") 15 | 16 | 17 | d = zroya.show(t, on_click=onclick, on_dismiss=ondismiss) 18 | print("Status: {}".format(d)) 19 | 20 | time.sleep(2) -------------------------------------------------------------------------------- /tests/test_hide.py: -------------------------------------------------------------------------------- 1 | import zroya 2 | import unittest 3 | 4 | class zroya_hide(unittest.TestCase): 5 | 6 | def test_NoParam(self): 7 | self.assertRaises(TypeError, lambda: zroya.hide()) 8 | 9 | def test_BadType(self): 10 | self.assertRaises(ValueError, lambda: zroya.hide("test")) 11 | 12 | def test_NegativeId(self): 13 | self.assertRaises(ValueError, lambda: zroya.hide(-1)) 14 | 15 | def test_ProperParam(self): 16 | t = zroya.Template(zroya.TemplateType.Text1) 17 | nid = zroya.show(t) 18 | self.assertTrue(zroya.hide(nid)) 19 | 20 | def test_ProperParamKeywords(self): 21 | t = zroya.Template(zroya.TemplateType.Text1) 22 | notID = zroya.show(t) 23 | self.assertTrue(zroya.hide(nid=notID)) 24 | 25 | 26 | if __name__ == "__main__": 27 | unittest.main() 28 | -------------------------------------------------------------------------------- /tests/test_init.py: -------------------------------------------------------------------------------- 1 | import zroya 2 | import unittest 3 | 4 | class zroya_init(unittest.TestCase): 5 | 6 | def test_NoParam(self): 7 | self.assertRaises(ValueError, lambda: zroya.init()) 8 | 9 | def test_FewParams(self): 10 | self.assertRaises(ValueError, lambda: zroya.init("a", "b")) 11 | 12 | def test_FewParamsKeywords(self): 13 | self.assertRaises(ValueError, lambda: zroya.init(app_name="a", company_name="b")) 14 | 15 | def test_EmptyParams(self): 16 | self.assertRaises(ValueError, lambda: zroya.init("", "", "", "", "")) 17 | 18 | def test_EmptyParamsKeywoards(self): 19 | self.assertRaises(ValueError, lambda: zroya.init( 20 | app_name="", company_name="", product_name="", sub_product="", version="") 21 | ) 22 | 23 | def test_ProperInit(self): 24 | self.assertTrue(zroya.init("a", "b", "c", "d", "e")) 25 | 26 | def test_ProperInitKeywords(self): 27 | self.assertTrue(zroya.init(app_name="a", company_name="b", product_name="c", sub_product="d", version="e")) 28 | 29 | if __name__ == "__main__": 30 | unittest.main() 31 | 32 | -------------------------------------------------------------------------------- /tests/test_show.py: -------------------------------------------------------------------------------- 1 | import zroya 2 | import unittest 3 | import time 4 | 5 | 6 | def on_click(id): 7 | pass 8 | 9 | 10 | class zroya_show(unittest.TestCase): 11 | 12 | def test_NoParam(self): 13 | self.assertRaises(TypeError, lambda: zroya.show()) 14 | 15 | def test_FewParams(self): 16 | self.assertRaises(TypeError, lambda: zroya.show(on_click=on_click)) 17 | 18 | def test_BadType(self): 19 | self.assertRaises(ValueError, lambda: zroya.show(None)) 20 | 21 | def test_ProperParams(self): 22 | t = zroya.Template(zroya.TemplateType.ImageAndText1) 23 | self.assertIsInstance(zroya.show(t), int) 24 | 25 | if __name__ == "__main__": 26 | unittest.main() 27 | -------------------------------------------------------------------------------- /tests/test_template.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import os 3 | import zroya 4 | 5 | class zroya_Template(unittest.TestCase): 6 | 7 | ### CONSTRUCTOR 8 | 9 | def test_constructor_EmptyParams(self): 10 | 11 | self.assertRaises(ValueError, lambda: zroya.Template()) 12 | 13 | def test_constructor_InvalidParams(self): 14 | self.assertRaises(ValueError, lambda: zroya.Template(-1)) 15 | 16 | def test_constructor_InvalidParams2(self): 17 | self.assertRaises(ValueError, lambda: zroya.Template(50)) 18 | 19 | def test_constructor_ProperParams(self): 20 | self.assertIsInstance(zroya.Template(zroya.TemplateType.Text1), zroya.Template) 21 | 22 | ### FIRST LINE 23 | 24 | def test_setFirstLine_EmptyParams(self): 25 | template = zroya.Template(zroya.TemplateType.Text1) 26 | self.assertRaises(TypeError, lambda: template.setFirstLine()) 27 | 28 | def test_setFirstLine_InvalidParams(self): 29 | template = zroya.Template(zroya.TemplateType.Text1) 30 | self.assertRaises(TypeError, lambda: template.setFirstLine(-1)) 31 | 32 | def test_setFirstLine_ProperParams(self): 33 | template = zroya.Template(zroya.TemplateType.Text1) 34 | self.assertTrue(template.setFirstLine("Test")) 35 | 36 | def test_getFirstLine_ProperParams(self): 37 | template = zroya.Template(zroya.TemplateType.Text1) 38 | template.setFirstLine("Test") 39 | self.assertEqual(template.getFirstLine(), "Test") 40 | 41 | ### SECOND LINE 42 | 43 | def test_setSecondLine_EmptyParams(self): 44 | template = zroya.Template(zroya.TemplateType.Text2) 45 | self.assertRaises(TypeError, lambda: template.setSecondLine()) 46 | 47 | def test_setSecondLine_InvalidParams(self): 48 | template = zroya.Template(zroya.TemplateType.Text2) 49 | self.assertRaises(TypeError, lambda: template.setSecondLine(-1)) 50 | 51 | def test_setSecondLine_ProperParams(self): 52 | template = zroya.Template(zroya.TemplateType.Text2) 53 | template.setFirstLine("Test") 54 | self.assertTrue(template.setSecondLine("Test Line 2")) 55 | 56 | def test_getSecondLine_ProperParams(self): 57 | template = zroya.Template(zroya.TemplateType.Text2) 58 | template.setFirstLine("Test") 59 | template.setSecondLine("Test Line 2") 60 | self.assertEqual(template.getSecondLine(), "Test Line 2") 61 | 62 | def test_setSecondLine_UnsuportedTemplateType(self): 63 | template = zroya.Template(zroya.TemplateType.Text1) 64 | self.assertFalse(template.setSecondLine("Test Line 2")) 65 | 66 | ### THIRD LINE 67 | def test_setThirdLine_EmptyParams(self): 68 | template = zroya.Template(zroya.TemplateType.Text4) 69 | self.assertRaises(TypeError, lambda: template.setThirdLine()) 70 | 71 | def test_setThirdLine_InvalidParams(self): 72 | template = zroya.Template(zroya.TemplateType.Text4) 73 | self.assertRaises(TypeError, lambda: template.setThirdLine(-1)) 74 | 75 | def test_setThirdLine_ProperParams(self): 76 | template = zroya.Template(zroya.TemplateType.Text4) 77 | template.setFirstLine("Test") 78 | template.setSecondLine("Test2") 79 | self.assertTrue(template.setThirdLine("Test Line 3")) 80 | 81 | def test_getThirdLine_ProperParams(self): 82 | template = zroya.Template(zroya.TemplateType.Text4) 83 | template.setThirdLine("Test Line 3") 84 | self.assertEqual(template.getThirdLine(), "Test Line 3") 85 | 86 | def test_thirdLine_UnsuportedTemplateType(self): 87 | template = zroya.Template(zroya.TemplateType.Text1) 88 | self.assertFalse(template.setThirdLine("Test Line 2")) 89 | 90 | ### Expire 91 | 92 | def test_setExpiration_InvalidParams(self): 93 | template = zroya.Template(zroya.TemplateType.Text1) 94 | self.assertRaises(TypeError, lambda: template.setExpiration("Test")) 95 | 96 | def test_setExpiration_EmptyParams(self): 97 | template = zroya.Template(zroya.TemplateType.Text1) 98 | self.assertRaises(TypeError, lambda: template.setExpiration()) 99 | 100 | def test_setExpire_ProperParams(self): 101 | template = zroya.Template(zroya.TemplateType.Text1) 102 | self.assertTrue(template.setExpiration(10)) 103 | 104 | def test_getExpiration_ProperParams(self): 105 | template = zroya.Template(zroya.TemplateType.Text1) 106 | template.setExpiration(10) 107 | self.assertEqual(template.getExpiration(), 10) 108 | 109 | ### AUDIO 110 | 111 | def test_setAudio_InvalidParams(self): 112 | template = zroya.Template(zroya.TemplateType.Text1) 113 | self.assertRaises(ValueError, lambda: template.setAudio(-1)) 114 | 115 | def test_setAudio_EmptyParams(self): 116 | template = zroya.Template(zroya.TemplateType.Text1) 117 | self.assertRaises(TypeError, lambda: template.setAudio()) 118 | 119 | def test_setAudio_ProperParams(self): 120 | template = zroya.Template(zroya.TemplateType.Text1) 121 | self.assertTrue(template.setAudio(zroya.Audio.Mail)) 122 | 123 | def test_setAudio_ProperParams2(self): 124 | template = zroya.Template(zroya.TemplateType.Text1) 125 | self.assertTrue(template.setAudio(audio=zroya.Audio.Mail, mode=zroya.AudioMode.Loop)) 126 | 127 | def test_getAudio_ProperParams(self): 128 | template = zroya.Template(zroya.TemplateType.Text1) 129 | template.setAudio(zroya.Audio.IM, zroya.AudioMode.Silence) 130 | self.assertEqual(template.getAudio(), zroya.Audio.IM) 131 | 132 | ### IMAGE 133 | 134 | def test_setImage_InvalidParams(self): 135 | template = zroya.Template(zroya.TemplateType.ImageAndText1) 136 | self.assertRaises(ValueError, lambda: template.setImage(-1)) 137 | 138 | def test_setImage_EmptyParams(self): 139 | template = zroya.Template(zroya.TemplateType.ImageAndText1) 140 | self.assertRaises(TypeError, lambda: template.setImage()) 141 | 142 | def test_setImage_FileDoesNotExist(self): 143 | template = zroya.Template(zroya.TemplateType.ImageAndText1) 144 | self.assertRaises(FileNotFoundError, lambda: template.setImage("./non_existing_file.png")) 145 | 146 | def test_setImage_ProperParams(self): 147 | template = zroya.Template(zroya.TemplateType.ImageAndText1) 148 | self.assertTrue(template.setImage("./tests/files/image.png")) 149 | 150 | def test_getImage_ProperParams(self): 151 | template = zroya.Template(zroya.TemplateType.ImageAndText1) 152 | path = os.path.abspath("./tests/files/image.png") 153 | template.setImage(path) 154 | self.assertEqual(template.getImage(), path) 155 | -------------------------------------------------------------------------------- /zroya/__init__.py: -------------------------------------------------------------------------------- 1 | from _zroya import * 2 | from .template_enums import * 3 | from .dismiss_reason import * 4 | from .version import * 5 | -------------------------------------------------------------------------------- /zroya/dismiss_reason.py: -------------------------------------------------------------------------------- 1 | class DismissReason(object): 2 | 3 | """ 4 | This class represents a notification dismiss reason. It is passed to callback registered in on_dismiss parameter 5 | of :py:func:`zroya.show` function. 6 | 7 | You can print it to get a reason description or compare it with any of following attributes. 8 | """ 9 | 10 | User = 0 11 | """ 12 | The user dismissed the toast. 13 | """ 14 | 15 | App = 1 16 | """ 17 | The application hid the toast using :py:func:`zroya.hide`. 18 | """ 19 | 20 | Expired = 2 21 | """ 22 | The toast has expired. 23 | """ 24 | 25 | def __init__(self, reason): 26 | """ 27 | Create an instance of dismiss reason. Zroya uses this class to return a dismiss reason of notification back to 28 | zroya callback. For instance, when you create a notification with on_dismiss callback set: 29 | 30 | .. code-block:: python 31 | 32 | def myDismissCallback(notificationID, reason): 33 | print("Notification {} was dismissed by user. Reason: {}.".format(notificationID, reason)) 34 | 35 | # t is an instance of zroya.Template 36 | zroya.show(t, on_dismiss = myCallback) 37 | 38 | this class will be used as a second parameter 'reason'. Since this is kind of C->Python bridge class, you 39 | will probably never create an instance of it. 40 | 41 | Args: 42 | reason (int): Integer representation of C dismiss reason. 43 | """ 44 | 45 | self._reason = reason 46 | 47 | def __str__(self): 48 | 49 | # Make sure, numbers corresponds with actual dismiss reasons from Windows core: 50 | # Search ToastDismissalReason::ToastDismissalReason_UserCanceled in wintoastlib.h 51 | 52 | if self._reason == DismissReason.User: 53 | return "The user dismissed the toast." 54 | if self._reason == DismissReason.App: 55 | return "The application hid the toast using zroya.hide." 56 | if self._reason == DismissReason.Expired: 57 | return "The toast has expired." 58 | 59 | return "Unknown dismiss reason. If you are seeing this, please report it as a bug. Thank you." 60 | 61 | def __eq__(self, other): 62 | if isinstance(other, int): 63 | return other == self._reason 64 | 65 | return False 66 | 67 | def __ne__(self, other): 68 | return not other == self 69 | -------------------------------------------------------------------------------- /zroya/template_enums.py: -------------------------------------------------------------------------------- 1 | from enum import IntEnum, Enum 2 | 3 | 4 | class AudioMode(IntEnum): 5 | """ 6 | AudioMode is enumeration holds all valid parameters accepted by :py:meth:`zroya.Template.setAudio` method's `mode` 7 | parameter. 8 | 9 | Example: 10 | .. code-block:: python 11 | 12 | # t is an instance of zroya.Template 13 | t.setAudio( mode=zroya.AudioMode.Silence ) 14 | 15 | """ 16 | 17 | Default = 0 18 | """ 19 | Selected audio will be played only once. 20 | """ 21 | 22 | Silence = 1 23 | """ 24 | No audio is played at all. 25 | """ 26 | 27 | Loop = 2 28 | """ 29 | Play audio in loop until it is moved to Action Center. This time may vary due to different user 30 | configuration. 31 | """ 32 | 33 | 34 | class Audio(Enum): 35 | """ 36 | Audio enumeration contains values for accepted values for `audio` parameter of :py:meth:`zroya.Template.setAudio` 37 | method. 38 | 39 | Example: 40 | .. code-block:: python 41 | 42 | # t is an instance of zroya.Template 43 | t.setAudio( audio=zroya.Audio.IM ) 44 | 45 | """ 46 | 47 | Default = "ms-winsoundevent:Notification.Default" 48 | """ 49 | .. raw:: html 50 | 51 | 52 | 53 | """ 54 | 55 | IM = "ms-winsoundevent:Notification.IM" 56 | """ 57 | .. raw:: html 58 | 59 | 60 | 61 | """ 62 | 63 | Mail = "ms-winsoundevent:Notification.Mail" 64 | """ 65 | .. raw:: html 66 | 67 | 68 | 69 | """ 70 | 71 | Reminder = "ms-winsoundevent:Notification.Reminder" 72 | """ 73 | .. raw:: html 74 | 75 | 76 | 77 | """ 78 | 79 | SMS = "ms-winsoundevent:Notification.SMS" 80 | Alarm = "ms-winsoundevent:Notification.Looping.Alarm" 81 | """ 82 | .. raw:: html 83 | 84 | 85 | 86 | """ 87 | 88 | Alarm2 = "ms-winsoundevent:Notification.Looping.Alarm2" 89 | """ 90 | .. raw:: html 91 | 92 | 93 | 94 | """ 95 | 96 | Alarm3 = "ms-winsoundevent:Notification.Looping.Alarm3" 97 | """ 98 | .. raw:: html 99 | 100 | 101 | 102 | """ 103 | 104 | Alarm4 = "ms-winsoundevent:Notification.Looping.Alarm4" 105 | """ 106 | .. raw:: html 107 | 108 | 109 | 110 | """ 111 | 112 | Alarm5 = "ms-winsoundevent:Notification.Looping.Alarm5" 113 | """ 114 | .. raw:: html 115 | 116 | 117 | 118 | """ 119 | 120 | Alarm6 = "ms-winsoundevent:Notification.Looping.Alarm6" 121 | """ 122 | .. raw:: html 123 | 124 | 125 | 126 | """ 127 | 128 | Alarm7 = "ms-winsoundevent:Notification.Looping.Alarm7" 129 | """ 130 | .. raw:: html 131 | 132 | 133 | 134 | """ 135 | 136 | Alarm8 = "ms-winsoundevent:Notification.Looping.Alarm8" 137 | """ 138 | .. raw:: html 139 | 140 | 141 | 142 | """ 143 | 144 | Alarm9 = "ms-winsoundevent:Notification.Looping.Alarm9" 145 | """ 146 | .. raw:: html 147 | 148 | 149 | 150 | """ 151 | 152 | Alarm10 = "ms-winsoundevent:Notification.Looping.Alarm10" 153 | """ 154 | .. raw:: html 155 | 156 | 157 | 158 | """ 159 | 160 | Call = "ms-winsoundevent:Notification.Looping.Call" 161 | """ 162 | .. raw:: html 163 | 164 | 165 | 166 | """ 167 | 168 | Call2 = "ms-winsoundevent:Notification.Looping.Call2" 169 | """ 170 | .. raw:: html 171 | 172 | 173 | 174 | """ 175 | 176 | Call3 = "ms-winsoundevent:Notification.Looping.Call3" 177 | """ 178 | .. raw:: html 179 | 180 | 181 | 182 | """ 183 | 184 | Call4 = "ms-winsoundevent:Notification.Looping.Call4" 185 | """ 186 | .. raw:: html 187 | 188 | 189 | 190 | """ 191 | 192 | Call5 = "ms-winsoundevent:Notification.Looping.Call5" 193 | """ 194 | .. raw:: html 195 | 196 | 197 | 198 | """ 199 | 200 | Call6 = "ms-winsoundevent:Notification.Looping.Call6" 201 | """ 202 | .. raw:: html 203 | 204 | 205 | 206 | """ 207 | 208 | Call7 = "ms-winsoundevent:Notification.Looping.Call7" 209 | """ 210 | .. raw:: html 211 | 212 | 213 | 214 | """ 215 | 216 | Call8 = "ms-winsoundevent:Notification.Looping.Call8" 217 | """ 218 | .. raw:: html 219 | 220 | 221 | 222 | """ 223 | 224 | Call9 = "ms-winsoundevent:Notification.Looping.Call9" 225 | """ 226 | .. raw:: html 227 | 228 | 229 | 230 | """ 231 | 232 | Call10 = "ms-winsoundevent:Notification.Looping.Call10" 233 | """ 234 | .. raw:: html 235 | 236 | 237 | 238 | """ 239 | 240 | 241 | class TemplateType(IntEnum): 242 | """ 243 | All possible values for :py:class:`zroya.Template` constructor. 244 | 245 | Example: 246 | .. code-block:: python 247 | 248 | zroya.Template(zroya.TemplateType.ImageAndText2) 249 | 250 | """ 251 | 252 | ImageAndText1 = 0 253 | """ 254 | A large image and a single string wrapped across three lines of text. 255 | """ 256 | 257 | ImageAndText2 = 1 258 | """ 259 | A large image, one string of bold text on the first line, one string of regular text wrapped across the 260 | second and third lines. 261 | """ 262 | 263 | ImageAndText3 = 2 264 | """ 265 | A large image, one string of bold text wrapped across the first two lines, one string of regular text on 266 | the third line. 267 | """ 268 | 269 | ImageAndText4 = 3 270 | """ 271 | A large image, one string of bold text on the first line, one string of regular text on the second line, 272 | one string of regular text on the third line. 273 | """ 274 | 275 | Text1 = 4 276 | """ 277 | Single string wrapped across three lines of text. 278 | """ 279 | 280 | Text2 = 5 281 | """ 282 | One string of bold text on the first line, one string of regular text wrapped across the second and third 283 | lines. 284 | """ 285 | 286 | Text3 = 6 287 | """ 288 | One string of bold text wrapped across the first two lines, one string of regular text on the third line. 289 | """ 290 | 291 | Text4 = 7 292 | """ 293 | One string of bold text on the first line, one string of regular text on the second line, one string of 294 | regular text on the third line. 295 | """ 296 | -------------------------------------------------------------------------------- /zroya/version.py: -------------------------------------------------------------------------------- 1 | __version__ = "0.2.4" 2 | __release__ = "0.2.4" 3 | --------------------------------------------------------------------------------