Skip to content

Commit 579f842

Browse files
committed
Initial commit
0 parents  commit 579f842

26 files changed

Lines changed: 11180 additions & 0 deletions

.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
addon/doc/*.css
2+
addon/doc/en/
3+
*_docHandler.py
4+
*.html
5+
*.ini
6+
*.mo
7+
*.pot
8+
*.py[co]
9+
*.nvda-addon
10+
.sconsign.dblite

COPYING.txt

Lines changed: 340 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
#__init__.py
2+
# Copyright (C) 2022 Beqa Gozalishvili <beqaprogger@gmail.com>
3+
#This file is covered by the GNU General Public License.
4+
#See the file COPYING for more details.
5+
6+
import addonHandler
7+
import config
8+
import globalPluginHandler
9+
import os
10+
from . import psutil
11+
import queueHandler
12+
import threading
13+
import time
14+
import tones
15+
import ui
16+
17+
from . import interface
18+
from .const import *
19+
20+
addonHandler.initTranslation()
21+
22+
config.conf.spec[addonName]=confspec
23+
24+
25+
class GlobalPlugin(globalPluginHandler.GlobalPlugin):
26+
27+
def __init__(self, *args, **kwargs):
28+
super().__init__(*args, **kwargs)
29+
self.addonConf = config.conf[addonName]
30+
self.cpuThread = None
31+
self.thEvent = threading.Event()
32+
if self.addonConf["enabled"]:
33+
self.initialize()
34+
interface.addSettingsPanel(self.addonConf, self.onSave)
35+
36+
def initialize(self, restart=False):
37+
if restart:
38+
self.tearDown()
39+
self.cpuThread = threading.Thread(target=self.cpuMonitor)
40+
self.thEvent.clear()
41+
self.cpuThread.start()
42+
43+
def onSave(self, enabled):
44+
if not enabled:
45+
self.tearDown()
46+
return
47+
self.initialize(True)
48+
49+
def tearDown(self):
50+
if self.cpuThread is not None:
51+
self.thEvent.set()
52+
self.cpuThread.join()
53+
self.cpuThread = None
54+
55+
def terminate(self):
56+
super().terminate()
57+
self.tearDown()
58+
interface.removeSettingsPanel()
59+
60+
def cpuMonitor(self):
61+
while not self.thEvent.is_set():
62+
wait = self.thEvent.wait(self.addonConf["timeInterval"])
63+
if wait:
64+
break
65+
cpuPercent = psutil.cpu_percent(0.1)
66+
if cpuPercent < self.addonConf["cpuThreshold"]:
67+
continue
68+
volume = self.addonConf["beepVol"]
69+
tones.beep(self.addonConf["beepFreq"], self.addonConf["beepLen"], left=volume, right=volume)
70+
processes = []
71+
pids = psutil.pids()[2:]
72+
for pid in pids:
73+
time.sleep(0.001)
74+
try:
75+
proc = psutil.Process(pid)
76+
except psutil.NoSuchProcess:
77+
continue
78+
proc.cpu_percent()
79+
processes.append(proc)
80+
time.sleep(0.1)
81+
try:
82+
pData = [(p.name(), p.cpu_percent()) for p in processes]
83+
except psutil.NoSuchProcess:
84+
continue
85+
pData = sorted(pData, key=lambda k: k[1])
86+
highest = round(pData[-1][1] / os.cpu_count(), 2)
87+
if highest == 0.0:
88+
continue
89+
queueHandler.queueFunction(queueHandler.eventQueue, ui.message, _("{processName} loaded CPU by {processLoadPercent}%").format(processName=pData[-1][0], processLoadPercent=highest))
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#const.py
2+
# Copyright (C) 2022 Beqa Gozalishvili <beqaprogger@gmail.com>
3+
#This file is covered by the GNU General Public License.
4+
#See the file COPYING for more details.
5+
6+
import addonHandler
7+
8+
confspec={
9+
"enabled": 'boolean(default=True)',
10+
"cpuThreshold": "integer(0,100,default=95)",
11+
"timeInterval": "integer(default=30)",
12+
"beepFreq": "integer(default=900)",
13+
"beepLen": "integer(default=100)",
14+
"beepVol": "integer(default=50)"
15+
}
16+
17+
addon = addonHandler.getCodeAddon()
18+
addonName = addon.name
19+
addonSummary = addon.manifest["summary"]
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#donatedialog.py
2+
# Copyright (C) 2022 Beqa Gozalishvili <beqaprogger@gmail.com>
3+
#This file is covered by the GNU General Public License.
4+
#See the file COPYING for more details.
5+
6+
import addonHandler
7+
import gui
8+
import webbrowser
9+
import wx
10+
11+
addonHandler.initTranslation()
12+
13+
14+
class DonationDialog(gui.nvdaControls.MessageDialog):
15+
YOOMONEY_URL = "https://yoomoney.ru/to/4100117727255296"
16+
PAYPAL_URL = "https://paypal.me/gozaltech"
17+
18+
def __init__(self, parent, title, message):
19+
super().__init__(parent, title, message, dialogType=gui.nvdaControls.MessageDialog.DIALOG_TYPE_WARNING)
20+
21+
def _addButtons(self, buttonHelper):
22+
paypalBtn = buttonHelper.addButton(self, label=_("Donate via Paypal"), name="PAYPAL_URL")
23+
yoomoneyBtn = buttonHelper.addButton(self, label=_("Donate via Yoomoney"), name="YOOMONEY_URL")
24+
paypalBtn.Bind(wx.EVT_BUTTON, self.onDonate)
25+
yoomoneyBtn.Bind(wx.EVT_BUTTON, self.onDonate)
26+
cancelBtn = buttonHelper.addButton(self, id=wx.ID_CANCEL)
27+
cancelBtn.Bind(wx.EVT_BUTTON, lambda evt: self.EndModal(wx.CANCEL))
28+
29+
def onDonate(self, evt):
30+
donateBtn = evt.GetEventObject()
31+
donateUrl = getattr(self, donateBtn.Name)
32+
webbrowser.open(donateUrl)
33+
self.EndModal(wx.OK)
34+
35+
def requestDonations(parentWindow):
36+
addon = addonHandler.getCodeAddon()
37+
addonName = addon.name
38+
title = _("Request for contributions to {name}").format(name=addonName)
39+
message = _(""" {name} is a free add-on for NVDA.
40+
You can make a donation to its author to support further developments of this and other free projects.
41+
Do you want to donate now? Choose one of the available payment methods. You will be redirected to the corresponding website to complete a donation""").format(name=addonName)
42+
return DonationDialog(parentWindow, title, message).ShowModal()
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#interface.py
2+
# Copyright (C) 2022 Beqa Gozalishvili <beqaprogger@gmail.com>
3+
#This file is covered by the GNU General Public License.
4+
#See the file COPYING for more details.
5+
6+
import addonHandler
7+
import gui
8+
import wx
9+
10+
from .const import *
11+
from .donatedialog import requestDonations
12+
13+
addonHandler.initTranslation()
14+
15+
16+
class CPUMonSettingsPanel(gui.SettingsPanel):
17+
title = addonSummary
18+
19+
def makeSettings(self, sizer):
20+
sHelper = gui.guiHelper.BoxSizerHelper(self, sizer=sizer)
21+
self.enableAddonChk = sHelper.addItem(wx.CheckBox(self, label=_("Enable addon")))
22+
self.enableAddonChk.SetValue(self.addonConf["enabled"])
23+
self.cpuThresholdSpin = sHelper.addLabeledControl(_("Minimum threshold for monitoring CPU load (in percents):"), gui.nvdaControls.SelectOnFocusSpinCtrl, min=5, max=100, initial=self.addonConf["cpuThreshold"])
24+
self.timeIntervalSpin = sHelper.addLabeledControl(_("Monitor update interval (in seconds):"), gui.nvdaControls.SelectOnFocusSpinCtrl, min=5, initial=self.addonConf["timeInterval"])
25+
self.beepFreqSpin = sHelper.addLabeledControl(_("Beep frequency for CPU load indication (in HZ):"), gui.nvdaControls.SelectOnFocusSpinCtrl, min=10, max=3000, initial=self.addonConf["beepFreq"])
26+
self.beepLenSpin = sHelper.addLabeledControl(_("Beep lenth for CPU load indication (in milliseconds):"), gui.nvdaControls.SelectOnFocusSpinCtrl, min=50, max=5000, initial=self.addonConf["beepLen"])
27+
self.beepVolSlider = sHelper.addLabeledControl(_("Beep volume for CPU load indication:"), gui.nvdaControls.EnhancedInputSlider, minValue=0, maxValue=100, value=self.addonConf["beepVol"])
28+
self.donateBtn = sHelper.addItem(wx.Button(self, label=_("Support an author with donation...")))
29+
self.donateBtn.Bind(wx.EVT_BUTTON, self.onDonate)
30+
31+
def onDonate(self, evt):
32+
requestDonations(self)
33+
34+
def onSave(self):
35+
enabled = self.enableAddonChk.GetValue()
36+
self.addonConf["enabled"] = enabled
37+
self.addonConf["cpuThreshold"] = self.cpuThresholdSpin.GetValue()
38+
self.addonConf["timeInterval"] = self.timeIntervalSpin.GetValue()
39+
self.addonConf["beepFreq"] = self.beepFreqSpin.GetValue()
40+
self.addonConf["beepLen"] = self.beepLenSpin.GetValue()
41+
self.addonConf["beepVol"] = self.beepVolSlider.GetValue()
42+
self.onSaveCallback(enabled)
43+
44+
45+
def addSettingsPanel(configSection, onSaveCallback):
46+
CPUMonSettingsPanel.addonConf = configSection
47+
CPUMonSettingsPanel.onSaveCallback = onSaveCallback
48+
gui.settingsDialogs.NVDASettingsDialog.categoryClasses.append(CPUMonSettingsPanel)
49+
50+
def removeSettingsPanel():
51+
gui.settingsDialogs.NVDASettingsDialog.categoryClasses.remove(CPUMonSettingsPanel)

0 commit comments

Comments
 (0)