summaryrefslogtreecommitdiff
path: root/external/plyer/platforms/win
diff options
context:
space:
mode:
Diffstat (limited to 'external/plyer/platforms/win')
-rw-r--r--external/plyer/platforms/win/__init__.py0
-rw-r--r--external/plyer/platforms/win/battery.py21
-rw-r--r--external/plyer/platforms/win/email.py34
-rw-r--r--external/plyer/platforms/win/filechooser.py112
-rw-r--r--external/plyer/platforms/win/libs/__init__.py0
-rw-r--r--external/plyer/platforms/win/libs/balloontip.py145
-rw-r--r--external/plyer/platforms/win/libs/batterystatus.py13
-rw-r--r--external/plyer/platforms/win/libs/win_api_defs.py200
-rw-r--r--external/plyer/platforms/win/notification.py13
-rw-r--r--external/plyer/platforms/win/tts.py16
-rw-r--r--external/plyer/platforms/win/uniqueid.py21
11 files changed, 575 insertions, 0 deletions
diff --git a/external/plyer/platforms/win/__init__.py b/external/plyer/platforms/win/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/external/plyer/platforms/win/__init__.py
diff --git a/external/plyer/platforms/win/battery.py b/external/plyer/platforms/win/battery.py
new file mode 100644
index 0000000..04006f8
--- /dev/null
+++ b/external/plyer/platforms/win/battery.py
@@ -0,0 +1,21 @@
+from plyer.platforms.win.libs.batterystatus import battery_status
+from plyer.facades import Battery
+
+
+class WinBattery(Battery):
+ def _get_state(self):
+ status = {"isCharging": None, "percentage": None}
+
+ query = battery_status()
+
+ if (not query):
+ return status
+
+ status["isCharging"] = query["BatteryFlag"] == 8
+ status["percentage"] = query["BatteryLifePercent"]
+
+ return status
+
+
+def instance():
+ return WinBattery()
diff --git a/external/plyer/platforms/win/email.py b/external/plyer/platforms/win/email.py
new file mode 100644
index 0000000..e33f5cf
--- /dev/null
+++ b/external/plyer/platforms/win/email.py
@@ -0,0 +1,34 @@
+import os
+try:
+ from urllib.parse import quote
+except ImportError:
+ from urllib import quote
+from plyer.facades import Email
+
+
+class WindowsEmail(Email):
+ def _send(self, **kwargs):
+ recipient = kwargs.get('recipient')
+ subject = kwargs.get('subject')
+ text = kwargs.get('text')
+
+ uri = "mailto:"
+ if recipient:
+ uri += str(recipient)
+ if subject:
+ uri += "?" if not "?" in uri else "&"
+ uri += "subject="
+ uri += quote(str(subject))
+ if text:
+ uri += "?" if not "?" in uri else "&"
+ uri += "body="
+ uri += quote(str(text))
+
+ try:
+ os.startfile(uri)
+ except WindowsError:
+ print("Warning: unable to find a program able to send emails.")
+
+
+def instance():
+ return WindowsEmail()
diff --git a/external/plyer/platforms/win/filechooser.py b/external/plyer/platforms/win/filechooser.py
new file mode 100644
index 0000000..4d284dc
--- /dev/null
+++ b/external/plyer/platforms/win/filechooser.py
@@ -0,0 +1,112 @@
+'''
+Windows file chooser
+--------------------
+'''
+
+from plyer.facades import FileChooser
+from win32com.shell import shell, shellcon
+import os
+import win32gui
+import win32con
+import pywintypes
+
+
+class Win32FileChooser(object):
+ '''A native implementation of NativeFileChooser using the
+ Win32 API on Windows.
+
+ Not Implemented features (all dialogs):
+ * preview
+ * icon
+
+ Not implemented features (in directory selection only - it's limited
+ by Windows itself):
+ * preview
+ * window-icon
+ * multiple
+ * show_hidden
+ * filters
+ * path
+ '''
+
+ path = None
+ multiple = False
+ filters = []
+ preview = False
+ title = None
+ icon = None
+ show_hidden = False
+
+ def __init__(self, **kwargs):
+ # Simulate Kivy's behavior
+ for i in kwargs:
+ setattr(self, i, kwargs[i])
+
+ def run(self):
+ try:
+ if self.mode != "dir":
+ args = {}
+
+ if self.path:
+ args["InitialDir"] = os.path.dirname(self.path)
+ path = os.path.splitext(os.path.dirname(self.path))
+ args["File"] = path[0]
+ args["DefExt"] = path[1]
+ args["Title"] = self.title if self.title else "Pick a file..."
+ args["CustomFilter"] = 'Other file types\x00*.*\x00'
+ args["FilterIndex"] = 1
+
+ filters = ""
+ for f in self.filters:
+ if type(f) == str:
+ filters += (f + "\x00") * 2
+ else:
+ filters += f[0] + "\x00" + ";".join(f[1:]) + "\x00"
+ args["Filter"] = filters
+
+ flags = (win32con.OFN_EXTENSIONDIFFERENT |
+ win32con.OFN_OVERWRITEPROMPT)
+ if self.multiple:
+ flags |= win32con.OFN_ALLOWmultiple | win32con.OFN_EXPLORER
+ if self.show_hidden:
+ flags |= win32con.OFN_FORCESHOWHIDDEN
+ args["Flags"] = flags
+
+ if self.mode == "open":
+ self.fname, _, _ = win32gui.GetOpenFileNameW(**args)
+ elif self.mode == "save":
+ self.fname, _, _ = win32gui.GetSaveFileNameW(**args)
+
+ if self.fname:
+ if self.multiple:
+ seq = str(self.fname).split("\x00")
+ dir_n, base_n = seq[0], seq[1:]
+ self.selection = [os.path.join(dir_n, i)
+ for i in base_n]
+ else:
+ self.selection = str(self.fname).split("\x00")
+ else:
+ # From http://goo.gl/UDqCqo
+ pidl, display_name, image_list = shell.SHBrowseForFolder(
+ win32gui.GetDesktopWindow(),
+ None,
+ self.title if self.title else "Pick a folder...",
+ 0, None, None
+ )
+ self.selection = [str(shell.SHGetPathFromIDList(pidl))]
+
+ return self.selection
+ except (RuntimeError, pywintypes.error):
+ return None
+
+
+class WinFileChooser(FileChooser):
+ '''FileChooser implementation for Windows, using win3all.
+ '''
+
+ def _file_selection_dialog(self, **kwargs):
+ return Win32FileChooser(**kwargs).run()
+
+
+def instance():
+ return WinFileChooser()
diff --git a/external/plyer/platforms/win/libs/__init__.py b/external/plyer/platforms/win/libs/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/external/plyer/platforms/win/libs/__init__.py
diff --git a/external/plyer/platforms/win/libs/balloontip.py b/external/plyer/platforms/win/libs/balloontip.py
new file mode 100644
index 0000000..171b25f
--- /dev/null
+++ b/external/plyer/platforms/win/libs/balloontip.py
@@ -0,0 +1,145 @@
+# -- coding: utf-8 --
+
+__all__ = ('WindowsBalloonTip', 'balloon_tip')
+
+
+import time
+import ctypes
+from plyer.platforms.win.libs import win_api_defs
+from plyer.compat import PY2
+from threading import RLock
+
+
+WS_OVERLAPPED = 0x00000000
+WS_SYSMENU = 0x00080000
+WM_DESTROY = 2
+CW_USEDEFAULT = 8
+
+LR_LOADFROMFILE = 16
+LR_DEFAULTSIZE = 0x0040
+IDI_APPLICATION = 32512
+IMAGE_ICON = 1
+
+NOTIFYICON_VERSION_4 = 4
+NIM_ADD = 0
+NIM_MODIFY = 1
+NIM_DELETE = 2
+NIM_SETVERSION = 4
+NIF_MESSAGE = 1
+NIF_ICON = 2
+NIF_TIP = 4
+NIF_INFO = 0x10
+NIIF_USER = 4
+NIIF_LARGE_ICON = 0x20
+
+
+class WindowsBalloonTip(object):
+
+ _class_atom = 0
+ _wnd_class_ex = None
+ _hwnd = None
+ _hicon = None
+ _balloon_icon = None
+ _notify_data = None
+ _count = 0
+ _lock = RLock()
+
+ @staticmethod
+ def _get_unique_id():
+ WindowsBalloonTip._lock.acquire()
+ val = WindowsBalloonTip._count
+ WindowsBalloonTip._count += 1
+ WindowsBalloonTip._lock.release()
+ return val
+
+ def __init__(self, title, message, app_name, app_icon='', timeout=10):
+ ''' app_icon if given is a icon file.
+ '''
+
+ wnd_class_ex = win_api_defs.get_WNDCLASSEXW()
+ class_name = 'PlyerTaskbar' + str(WindowsBalloonTip._get_unique_id())
+ if PY2:
+ class_name = class_name.decode('utf8')
+ wnd_class_ex.lpszClassName = class_name
+ # keep ref to it as long as window is alive
+ wnd_class_ex.lpfnWndProc =\
+ win_api_defs.WindowProc(win_api_defs.DefWindowProcW)
+ wnd_class_ex.hInstance = win_api_defs.GetModuleHandleW(None)
+ if wnd_class_ex.hInstance is None:
+ raise Exception('Could not get windows module instance.')
+ class_atom = win_api_defs.RegisterClassExW(wnd_class_ex)
+ if class_atom == 0:
+ raise Exception('Could not register the PlyerTaskbar class.')
+ self._class_atom = class_atom
+ self._wnd_class_ex = wnd_class_ex
+
+ # create window
+ self._hwnd = win_api_defs.CreateWindowExW(0, class_atom,
+ '', WS_OVERLAPPED, 0, 0, CW_USEDEFAULT,
+ CW_USEDEFAULT, None, None, wnd_class_ex.hInstance, None)
+ if self._hwnd is None:
+ raise Exception('Could not get create window.')
+ win_api_defs.UpdateWindow(self._hwnd)
+
+ # load icon
+ if app_icon:
+ icon_flags = LR_LOADFROMFILE | LR_DEFAULTSIZE
+ hicon = win_api_defs.LoadImageW(None, app_icon, IMAGE_ICON, 0, 0,
+ icon_flags)
+ if hicon is None:
+ raise Exception('Could not load icon {}'.
+ format(icon_path_name))
+ self._balloon_icon = self._hicon = hicon
+ else:
+ self._hicon = win_api_defs.LoadIconW(None,
+ ctypes.cast(IDI_APPLICATION, win_api_defs.LPCWSTR))
+ self.notify(title, message, app_name)
+ if timeout:
+ time.sleep(timeout)
+
+ def __del__(self):
+ self.remove_notify()
+ if self._hicon is not None:
+ win_api_defs.DestroyIcon(self._hicon)
+ if self._wnd_class_ex is not None:
+ win_api_defs.UnregisterClassW(self._class_atom,
+ self._wnd_class_ex.hInstance)
+ if self._hwnd is not None:
+ win_api_defs.DestroyWindow(self._hwnd)
+
+ def notify(self, title, message, app_name):
+ ''' Displays a balloon in the systray. Can be called multiple times
+ with different parameter values.
+ '''
+ self.remove_notify()
+ # add icon and messages to window
+ hicon = self._hicon
+ flags = NIF_TIP | NIF_INFO
+ icon_flag = 0
+ if hicon is not None:
+ flags |= NIF_ICON
+ # if icon is default app's one, don't display it in message
+ if self._balloon_icon is not None:
+ icon_flag = NIIF_USER | NIIF_LARGE_ICON
+ notify_data = win_api_defs.get_NOTIFYICONDATAW(0, self._hwnd,
+ id(self), flags, 0, hicon, app_name, 0, 0, message,
+ NOTIFYICON_VERSION_4, title, icon_flag, win_api_defs.GUID(),
+ self._balloon_icon)
+
+ self._notify_data = notify_data
+ if not win_api_defs.Shell_NotifyIconW(NIM_ADD, notify_data):
+ raise Exception('Shell_NotifyIconW failed.')
+ if not win_api_defs.Shell_NotifyIconW(NIM_SETVERSION,
+ notify_data):
+ raise Exception('Shell_NotifyIconW failed.')
+
+ def remove_notify(self):
+ '''Removes the notify balloon, if displayed.
+ '''
+ if self._notify_data is not None:
+ win_api_defs.Shell_NotifyIconW(NIM_DELETE, self._notify_data)
+ self._notify_data = None
+
+
+def balloon_tip(**kwargs):
+ WindowsBalloonTip(**kwargs)
diff --git a/external/plyer/platforms/win/libs/batterystatus.py b/external/plyer/platforms/win/libs/batterystatus.py
new file mode 100644
index 0000000..ddb22cc
--- /dev/null
+++ b/external/plyer/platforms/win/libs/batterystatus.py
@@ -0,0 +1,13 @@
+__all__ = ('battery_status')
+
+
+import ctypes
+from plyer.platforms.win.libs import win_api_defs
+
+
+def battery_status():
+ status = win_api_defs.SYSTEM_POWER_STATUS()
+ if not win_api_defs.GetSystemPowerStatus(ctypes.pointer(status)):
+ raise Exception('Could not get system power status.')
+
+ return dict((field, getattr(status, field)) for field, _ in status._fields_)
diff --git a/external/plyer/platforms/win/libs/win_api_defs.py b/external/plyer/platforms/win/libs/win_api_defs.py
new file mode 100644
index 0000000..7aed430
--- /dev/null
+++ b/external/plyer/platforms/win/libs/win_api_defs.py
@@ -0,0 +1,200 @@
+''' Defines ctypes windows api.
+'''
+
+__all__ = ('GUID', 'get_DLLVERSIONINFO', 'MAKEDLLVERULL',
+ 'get_NOTIFYICONDATAW', 'CreateWindowExW', 'WindowProc',
+ 'DefWindowProcW', 'get_WNDCLASSEXW', 'GetModuleHandleW',
+ 'RegisterClassExW', 'UpdateWindow', 'LoadImageW',
+ 'Shell_NotifyIconW', 'DestroyIcon', 'UnregisterClassW',
+ 'DestroyWindow', 'LoadIconW')
+
+import ctypes
+from ctypes import Structure, windll, sizeof, POINTER, WINFUNCTYPE
+from ctypes.wintypes import (DWORD, HICON, HWND, UINT, WCHAR, WORD, BYTE,
+ LPCWSTR, INT, LPVOID, HINSTANCE, HMENU, LPARAM, WPARAM,
+ HBRUSH, HMODULE, ATOM, BOOL, HANDLE)
+LRESULT = LPARAM
+HRESULT = HANDLE
+HCURSOR = HICON
+
+
+class GUID(Structure):
+ _fields_ = [
+ ('Data1', DWORD),
+ ('Data2', WORD),
+ ('Data3', WORD),
+ ('Data4', BYTE * 8)
+ ]
+
+
+class DLLVERSIONINFO(Structure):
+ _fields_ = [
+ ('cbSize', DWORD),
+ ('dwMajorVersion', DWORD),
+ ('dwMinorVersion', DWORD),
+ ('dwBuildNumber', DWORD),
+ ('dwPlatformID', DWORD),
+ ]
+
+
+def get_DLLVERSIONINFO(*largs):
+ version_info = DLLVERSIONINFO(*largs)
+ version_info.cbSize = sizeof(DLLVERSIONINFO)
+ return version_info
+
+
+def MAKEDLLVERULL(major, minor, build, sp):
+ return (major << 48) | (minor << 32) | (build << 16) | sp
+
+
+NOTIFYICONDATAW_fields = [
+ ("cbSize", DWORD),
+ ("hWnd", HWND),
+ ("uID", UINT),
+ ("uFlags", UINT),
+ ("uCallbackMessage", UINT),
+ ("hIcon", HICON),
+ ("szTip", WCHAR * 128),
+ ("dwState", DWORD),
+ ("dwStateMask", DWORD),
+ ("szInfo", WCHAR * 256),
+ ("uVersion", UINT),
+ ("szInfoTitle", WCHAR * 64),
+ ("dwInfoFlags", DWORD),
+ ("guidItem", GUID),
+ ("hBalloonIcon", HICON),
+]
+
+
+class NOTIFYICONDATAW(Structure):
+ _fields_ = NOTIFYICONDATAW_fields[:]
+
+
+class NOTIFYICONDATAW_V3(Structure):
+ _fields_ = NOTIFYICONDATAW_fields[:-1]
+
+
+class NOTIFYICONDATAW_V2(Structure):
+ _fields_ = NOTIFYICONDATAW_fields[:-2]
+
+
+class NOTIFYICONDATAW_V1(Structure):
+ _fields_ = NOTIFYICONDATAW_fields[:6]
+
+
+NOTIFYICONDATA_V3_SIZE = sizeof(NOTIFYICONDATAW_V3)
+NOTIFYICONDATA_V2_SIZE = sizeof(NOTIFYICONDATAW_V2)
+NOTIFYICONDATA_V1_SIZE = sizeof(NOTIFYICONDATAW_V1)
+
+
+def get_NOTIFYICONDATAW(*largs):
+ notify_data = NOTIFYICONDATAW(*largs)
+
+ # get shell32 version to find correct NOTIFYICONDATAW size
+ DllGetVersion = windll.Shell32.DllGetVersion
+ DllGetVersion.argtypes = [POINTER(DLLVERSIONINFO)]
+ DllGetVersion.restype = HRESULT
+
+ version = get_DLLVERSIONINFO()
+ if DllGetVersion(version):
+ raise Exception('Cannot get Windows version numbers.')
+ v = MAKEDLLVERULL(version.dwMajorVersion, version.dwMinorVersion,
+ version.dwBuildNumber, version.dwPlatformID)
+
+ # from the version info find the NOTIFYICONDATA size
+ if v >= MAKEDLLVERULL(6, 0, 6, 0):
+ notify_data.cbSize = sizeof(NOTIFYICONDATAW)
+ elif v >= MAKEDLLVERULL(6, 0, 0, 0):
+ notify_data.cbSize = NOTIFYICONDATA_V3_SIZE
+ elif v >= MAKEDLLVERULL(5, 0, 0, 0):
+ notify_data.cbSize = NOTIFYICONDATA_V2_SIZE
+ else:
+ notify_data.cbSize = NOTIFYICONDATA_V1_SIZE
+ return notify_data
+
+
+CreateWindowExW = windll.User32.CreateWindowExW
+CreateWindowExW.argtypes = [DWORD, ATOM, LPCWSTR, DWORD, INT, INT, INT, INT,
+ HWND, HMENU, HINSTANCE, LPVOID]
+CreateWindowExW.restype = HWND
+
+GetModuleHandleW = windll.Kernel32.GetModuleHandleW
+GetModuleHandleW.argtypes = [LPCWSTR]
+GetModuleHandleW.restype = HMODULE
+
+WindowProc = WINFUNCTYPE(LRESULT, HWND, UINT, WPARAM, LPARAM)
+DefWindowProcW = windll.User32.DefWindowProcW
+DefWindowProcW.argtypes = [HWND, UINT, WPARAM, LPARAM]
+DefWindowProcW.restype = LRESULT
+
+
+class WNDCLASSEXW(Structure):
+ _fields_ = [
+ ('cbSize', UINT),
+ ('style', UINT),
+ ('lpfnWndProc', WindowProc),
+ ('cbClsExtra', INT),
+ ('cbWndExtra', INT),
+ ('hInstance', HINSTANCE),
+ ('hIcon', HICON),
+ ('hCursor', HCURSOR),
+ ('hbrBackground', HBRUSH),
+ ('lpszMenuName', LPCWSTR),
+ ('lpszClassName', LPCWSTR),
+ ('hIconSm', HICON),
+ ]
+
+
+def get_WNDCLASSEXW(*largs):
+ wnd_class = WNDCLASSEXW(*largs)
+ wnd_class.cbSize = sizeof(WNDCLASSEXW)
+ return wnd_class
+
+RegisterClassExW = windll.User32.RegisterClassExW
+RegisterClassExW.argtypes = [POINTER(WNDCLASSEXW)]
+RegisterClassExW.restype = ATOM
+
+UpdateWindow = windll.User32.UpdateWindow
+UpdateWindow.argtypes = [HWND]
+UpdateWindow.restype = BOOL
+
+LoadImageW = windll.User32.LoadImageW
+LoadImageW.argtypes = [HINSTANCE, LPCWSTR, UINT, INT, INT, UINT]
+LoadImageW.restype = HANDLE
+
+Shell_NotifyIconW = windll.Shell32.Shell_NotifyIconW
+Shell_NotifyIconW.argtypes = [DWORD, POINTER(NOTIFYICONDATAW)]
+Shell_NotifyIconW.restype = BOOL
+
+DestroyIcon = windll.User32.DestroyIcon
+DestroyIcon.argtypes = [HICON]
+DestroyIcon.restype = BOOL
+
+UnregisterClassW = windll.User32.UnregisterClassW
+UnregisterClassW.argtypes = [ATOM, HINSTANCE]
+UnregisterClassW.restype = BOOL
+
+DestroyWindow = windll.User32.DestroyWindow
+DestroyWindow.argtypes = [HWND]
+DestroyWindow.restype = BOOL
+
+LoadIconW = windll.User32.LoadIconW
+LoadIconW.argtypes = [HINSTANCE, LPCWSTR]
+LoadIconW.restype = HICON
+
+
+class SYSTEM_POWER_STATUS(ctypes.Structure):
+ _fields_ = [
+ ('ACLineStatus', BYTE),
+ ('BatteryFlag', BYTE),
+ ('BatteryLifePercent', BYTE),
+ ('Reserved1', BYTE),
+ ('BatteryLifeTime', DWORD),
+ ('BatteryFullLifeTime', DWORD),
+ ]
+
+SystemPowerStatusP = ctypes.POINTER(SYSTEM_POWER_STATUS)
+
+GetSystemPowerStatus = ctypes.windll.kernel32.GetSystemPowerStatus
+GetSystemPowerStatus.argtypes = [SystemPowerStatusP]
+GetSystemPowerStatus.restype = BOOL
diff --git a/external/plyer/platforms/win/notification.py b/external/plyer/platforms/win/notification.py
new file mode 100644
index 0000000..ea46e08
--- /dev/null
+++ b/external/plyer/platforms/win/notification.py
@@ -0,0 +1,13 @@
+from threading import Thread as thread
+
+from plyer.facades import Notification
+from plyer.platforms.win.libs.balloontip import balloon_tip
+
+
+class WindowsNotification(Notification):
+ def _notify(self, **kwargs):
+ thread(target=balloon_tip, kwargs=kwargs).start()
+
+
+def instance():
+ return WindowsNotification()
diff --git a/external/plyer/platforms/win/tts.py b/external/plyer/platforms/win/tts.py
new file mode 100644
index 0000000..e2539c3
--- /dev/null
+++ b/external/plyer/platforms/win/tts.py
@@ -0,0 +1,16 @@
+import subprocess
+from plyer.facades import TTS
+from plyer.utils import whereis_exe
+
+
+class EspeakTextToSpeech(TTS):
+ ''' Speaks using the espeak program
+ '''
+ def _speak(self, **kwargs):
+ subprocess.call(["espeak", kwargs.get('message')])
+
+
+def instance():
+ if whereis_exe('espeak.exe'):
+ return EspeakTextToSpeech()
+ return TTS()
diff --git a/external/plyer/platforms/win/uniqueid.py b/external/plyer/platforms/win/uniqueid.py
new file mode 100644
index 0000000..bfcf996
--- /dev/null
+++ b/external/plyer/platforms/win/uniqueid.py
@@ -0,0 +1,21 @@
+try:
+ import _winreg as regedit
+except:
+ try:
+ import winreg as regedit
+ except:
+ raise NotImplemented()
+
+from plyer.facades import UniqueID
+
+
+class WinUniqueID(UniqueID):
+ def _get_uid(self):
+ hKey = regedit.OpenKey(regedit.HKEY_LOCAL_MACHINE,
+ r"SOFTWARE\\Microsoft\\Cryptography")
+ value, _ = regedit.QueryValueEx(hKey, "MachineGuid")
+ return value
+
+
+def instance():
+ return WinUniqueID()