-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.py
135 lines (118 loc) · 4.13 KB
/
index.py
1
2
3
4
5
6
7
8
9
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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
from PIL import Image, ImageDraw,ImageFont
from ctypes import cast, POINTER
from comtypes import CLSCTX_ALL
from pycaw.pycaw import AudioUtilities, IAudioEndpointVolume
from threading import Thread
from os.path import exists
from os import path, mkdir
import wx.adv
import wx
import time
APP_DATA_PATH = path.expandvars(r'%LOCALAPPDATA%\VolumeLevelTray')
class Audio:
"""Class"""
"""Class for sound info retrieval"""
def __init__(self):
devices = AudioUtilities.GetSpeakers()
interface = devices.Activate(IAudioEndpointVolume._iid_, CLSCTX_ALL, None)
self.volume = cast(interface, POINTER(IAudioEndpointVolume))
def get_volume(self):
"""Get integer number with range 0-100 which represents the volume percentage"""
return int(round(self.volume.GetMasterVolumeLevelScalar() * 100))
def is_muted(self):
"""Returns 1 if muted, 0 if not"""
return self.volume.GetMute()
def toggle_mute(self):
"""Toggles mute"""
self.volume.SetMute(not self.is_muted(), None)
class TaskBarIcon(wx.adv.TaskBarIcon):
"""Class for taskbar icon"""
tray_icon = path.join(APP_DATA_PATH, 'volume_level.ico')
font_type = ImageFont.truetype("arial.ttf", 45)
# icon is a square, so its size could be represented by a single number
size = 50
def __init__(self, frame):
wx.adv.TaskBarIcon.__init__(self)
self.frame = frame
# if icon is not found, it will be created
if not exists(TaskBarIcon.tray_icon):
TaskBarIcon.refresh_icon(0, False)
# set icon for the first time
self.update_icon()
def CreatePopupMenu(self):
"""Generate menu for the taskbar icon"""
menu = wx.Menu()
# exit menu item
exitItem = wx.MenuItem(menu, -1, 'Exit')
menu.Bind(wx.EVT_MENU, self.on_exit, id=exitItem.GetId())
menu.Append(exitItem)
return menu
@staticmethod
def refresh_icon(volume, is_muted):
"""Refresh icon with new volume level"""
new_img = Image.new('RGBA', (TaskBarIcon.size, TaskBarIcon.size), color = (255, 255, 255, 0))
drawed = ImageDraw.Draw(new_img)
# if muted, draw a red cross
if is_muted:
drawed.line([(0, 0), (TaskBarIcon.size, TaskBarIcon.size)], fill = (255,0,0,150), width = 8)
drawed.line([(0, TaskBarIcon.size), (TaskBarIcon.size, 0)], fill = (255,0,0,150), width = 8)
# draw volume level
drawed.text((0, 0), f"{volume}", fill=(255,255,255), font = TaskBarIcon.font_type)
# store image as the icon
new_img.save(TaskBarIcon.tray_icon)
def update_icon(self):
"""Set the icon for the taskbar icon"""
icon = wx.Icon(wx.Bitmap(TaskBarIcon.tray_icon))
self.SetIcon(icon, 'Volume level')
def on_exit(self, event):
"""Exit the application"""
self.frame.Close()
class IconUpdateThread(Thread):
"""Class for thread which updates the icon in infinite loop"""
def __init__(self, icon, audio):
Thread.__init__(self)
self.daemon = True
self.audio = audio
self.icon = icon
self.start()
def run(self):
while True:
# get volume level
currVolume = self.audio.get_volume()
# get mute status
is_muted = self.audio.is_muted()
# refresh icon
TaskBarIcon.refresh_icon(currVolume, is_muted)
self.icon.update_icon()
# pause for 0.2 seconds
time.sleep(.2)
class App(wx.Frame):
"""Class for main application"""
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "", size=(1,1))
wx.Panel(self)
self.Bind(wx.EVT_CLOSE, self.on_close)
if not exists(TaskBarIcon.tray_icon):
TaskBarIcon.refresh_icon(0, False)
# create taskbar icon
self.icon = TaskBarIcon(self)
# create audio object
self.audio = Audio()
# bind left click to mute function
self.icon.Bind(wx.adv.EVT_TASKBAR_LEFT_DOWN, self.mute)
# create thread which updates the icon
IconUpdateThread(self.icon, self.audio)
def mute(self, event):
"""Mute/unmute audio"""
self.audio.toggle_mute()
def on_close(self, event):
"""Destroy the icon on close"""
self.icon.RemoveIcon()
self.icon.Destroy()
self.Destroy()
if __name__ == "__main__":
if not exists(APP_DATA_PATH):
mkdir(APP_DATA_PATH)
wxApp = wx.App()
App()
wxApp.MainLoop()