If you want, post the code of that skin. Let's see how does it look (just to satisfy my curiosity).rlnoonan wrote:I do think there was something about that skin that wasn't visible on the screen. It may have been misbehaving and consuming more resources over time.
It is currently March 29th, 2024, 9:25 am
Rainmeter CPU util slowly rising over time
-
- Rainmeter Sage
- Posts: 16110
- Joined: October 11th, 2010, 6:27 pm
- Location: Gheorgheni, Romania
Re: Rainmeter CPU util slowly rising over time
-
- Posts: 26
- Joined: July 30th, 2018, 10:37 pm
Re: Rainmeter CPU util slowly rising over time
I really hate to say it, but I'm not certain what skin it was. I am pretty sure that it was ModernGadgets/Config, but when I went to get that skin's code I found that there are a number of sub-categories under Config and I didn't look close enough when I was unloading the skin (did it via the right click on the notification icon instead of through the application itself, so I didn't have to navigate the hierarchy of the skins).
However, I went through all of the ModernGadgets/Config skins and loaded each one, one at a time. Sure enough, the Setup skin does not show up on the screen. So I'm pretty sure the skin in question is ModernGadgets/Config/Setup (version 1.3.1). I have attached the Config.ini file associated with that skin. Is that the code you are looking for? If not, can you point me to where I would find the code? Also, here is the section for that skin in Rainmeter.ini:
[ModernGadgets\Config\Setup]
Active=0
WindowX=835
WindowY=525
ClickThrough=0
Draggable=1
SnapEdges=1
KeepOnScreen=1
AlwaysOnTop=0
A further update: after another 24 hours the Rainmeter utilization is holding steady at about 2%. So I definitely think the problem has been eliminated. I'll try a couple of those other experiments now. I did already try exiting RainMeter and then running it again, without that skin loaded. The utilization does not seem to go back to 1%, but picks up pretty much where it left off (but the memory allocated does seem to reset). Next I'll see if logging off works the same as a system restart.
However, I went through all of the ModernGadgets/Config skins and loaded each one, one at a time. Sure enough, the Setup skin does not show up on the screen. So I'm pretty sure the skin in question is ModernGadgets/Config/Setup (version 1.3.1). I have attached the Config.ini file associated with that skin. Is that the code you are looking for? If not, can you point me to where I would find the code? Also, here is the section for that skin in Rainmeter.ini:
[ModernGadgets\Config\Setup]
Active=0
WindowX=835
WindowY=525
ClickThrough=0
Draggable=1
SnapEdges=1
KeepOnScreen=1
AlwaysOnTop=0
A further update: after another 24 hours the Rainmeter utilization is holding steady at about 2%. So I definitely think the problem has been eliminated. I'll try a couple of those other experiments now. I did already try exiting RainMeter and then running it again, without that skin loaded. The utilization does not seem to go back to 1%, but picks up pretty much where it left off (but the memory allocated does seem to reset). Next I'll see if logging off works the same as a system restart.
You do not have the required permissions to view the files attached to this post.
-
- Rainmeter Sage
- Posts: 16110
- Joined: October 11th, 2010, 6:27 pm
- Location: Gheorgheni, Romania
Re: Rainmeter CPU util slowly rising over time
Are you sure? Because it is for me, see the attached image. That is how does it look like.rlnoonan wrote:Sure enough, the Setup skin does not show up on the screen.
Just to be sure, did you talk about the ModernGadgets\Config\Setup\Config.ini skin (I hope I didn't misunderstand)?
You do not have the required permissions to view the files attached to this post.
-
- Posts: 26
- Joined: July 30th, 2018, 10:37 pm
Re: Rainmeter CPU util slowly rising over time
Yes, that is the correct skin that I was referring to. I know it sounds bizarre, but I just tried it again to be sure and when the skin is loaded, I am not seeing it at all. I'm pretty sure I had seen that same window back when I first installed the skin and was messing around with it because I recognize the image you posted. Is it possible that something has gone wrong with the skin and that is why it was consuming more and more CPU (and probably memory too)? Or is it possible it has somehow been moved off the visible boundaries of the screen and that is why I can't see it?
-
- Rainmeter Sage
- Posts: 16110
- Joined: October 11th, 2010, 6:27 pm
- Location: Gheorgheni, Romania
Re: Rainmeter CPU util slowly rising over time
No, it doesn't sound bizarre, because the Config.ini skin is written into a bizarre way (if I can say so). When you click Close, the skin isn't unloaded, but just hidden. That's why once you close it, it is kept loaded, but never shown up again (I admit I didn't enter too deeply to see how it could be shown up again, but nor did I find an easy way to do it). And as such it indeed can cause CPU usage increase.rlnoonan wrote:I know it sounds bizarre, but I just tried it again to be sure and when the skin is loaded, I am not seeing it at all. I'm pretty sure I had seen that same window back when I first installed the skin and was messing around with it because I recognize the image you posted.
From my point of view, it's a weirdly written code. I can't say what was the author's intention, what he did want to achieve with a such action.
-
- Rainmeter Sage
- Posts: 16110
- Joined: October 11th, 2010, 6:27 pm
- Location: Gheorgheni, Romania
Re: Rainmeter CPU util slowly rising over time
Here is what you have to do to show up the Config.ini. First close it manually (right click the Rainmeter icon in Notification Area, the go to Skins -> ModernGadgets -> Config -> Setup and uncheck Config.ini. Open the skin's .ini file and modify the value of the loaded variable to 0, within the [Variables] section:
Now if try to load the skin, it is shown up (well probably initially an "Import settings backup?" question is shown, but if you click any of the Yes or No strings, the main window appears).
Unfortunately every time you're loading the skin, the loaded variable is rewritten, so you have to modify it manually every time. Probably I am missing something and there is a good reason of this variable, but I couldn't find it yet. Maybe you could ask the author what was his intention with that variable.
Code: Select all
[Variables]
...
loaded=0
Unfortunately every time you're loading the skin, the loaded variable is rewritten, so you have to modify it manually every time. Probably I am missing something and there is a good reason of this variable, but I couldn't find it yet. Maybe you could ask the author what was his intention with that variable.
-
- Posts: 26
- Joined: July 30th, 2018, 10:37 pm
Re: Rainmeter CPU util slowly rising over time
I was out of the office last week (so my computer was off most of the time) and spent this week watching my CPU utilization rise again. Today, after about 4 days of uptime the utilization had reached about 8-9% so I decided it definitely wasn't normal and I needed to start digging again. A few observations:
- I am now running with the SysInfo package with 38 different skins. Previously, when I thought I had this figured out and pinned to the "invisible" skin, I wasn't using this package for simplicity (a pain to unload 38 skins).
- I did test the logout vs. system restart and found that RainMeter dropped from 8-9% down to about 5% after a logout. A system restart brings it down to 1-2%, so logging out improves things, but something is still hanging around.
- I decided to start unloading the SysInfo skins one by one. Sure enough, I stumbled on three skins that seem to be the problem ones. I can load and unload these skins and watch the utilization rise and fall by around 3% each (did this before the logout test above). The three skins are:
- SysInfo->Strings->Software->TopProcess->Top-Process-Percent-Column.ini
- SysInfo->Strings->Software->Processes->Processes-Left.ini
- SysInfo->Strings->Software->Threads->Threads-Left.ini
- I'm now running with my normal layout minus these three skins, which includes the other 35 SysInfo skins, and things seem to be holding steady at 1-2%.
- I did try your suggestion about editing the config.ini file and it worked exactly as you said. It now shows up correctly if I edit that file each time. Thanks for the tip.
So there definitely seemed to be an issue with that "invisible" skin, but I think the real culprit may be these three skins. I'll keep my eye on things over the weekend.
In the meantime, is there anything that I can do to try to figure out (and hopefully fix) what might be going on with these skins? I really like the SysInfo package and top process is one of the pieces of info I really want, so I'd love to at least fix that one. I don't know anything about developing skins (I do have plenty of coding experience though). Is it all contained in the .ini files where I could experiment? Or is there other code elsewhere that I likely wouldn't have access to?
As always, thanks for the help.
- I am now running with the SysInfo package with 38 different skins. Previously, when I thought I had this figured out and pinned to the "invisible" skin, I wasn't using this package for simplicity (a pain to unload 38 skins).
- I did test the logout vs. system restart and found that RainMeter dropped from 8-9% down to about 5% after a logout. A system restart brings it down to 1-2%, so logging out improves things, but something is still hanging around.
- I decided to start unloading the SysInfo skins one by one. Sure enough, I stumbled on three skins that seem to be the problem ones. I can load and unload these skins and watch the utilization rise and fall by around 3% each (did this before the logout test above). The three skins are:
- SysInfo->Strings->Software->TopProcess->Top-Process-Percent-Column.ini
- SysInfo->Strings->Software->Processes->Processes-Left.ini
- SysInfo->Strings->Software->Threads->Threads-Left.ini
- I'm now running with my normal layout minus these three skins, which includes the other 35 SysInfo skins, and things seem to be holding steady at 1-2%.
- I did try your suggestion about editing the config.ini file and it worked exactly as you said. It now shows up correctly if I edit that file each time. Thanks for the tip.
So there definitely seemed to be an issue with that "invisible" skin, but I think the real culprit may be these three skins. I'll keep my eye on things over the weekend.
In the meantime, is there anything that I can do to try to figure out (and hopefully fix) what might be going on with these skins? I really like the SysInfo package and top process is one of the pieces of info I really want, so I'd love to at least fix that one. I don't know anything about developing skins (I do have plenty of coding experience though). Is it all contained in the .ini files where I could experiment? Or is there other code elsewhere that I likely wouldn't have access to?
As always, thanks for the help.
-
- Rainmeter Sage
- Posts: 16110
- Joined: October 11th, 2010, 6:27 pm
- Location: Gheorgheni, Romania
Re: Rainmeter CPU util slowly rising over time
Thanks rlnoonanfor for your trust, but unfortunately (for you) I can't answer now, because I'm not home and as such have no access to my computer. If someone else doesn't answer you, I will when I get home, around the middle of next week.
-
- Posts: 660
- Joined: June 25th, 2015, 7:02 pm
- Location: The Sky, USA
Re: Rainmeter CPU util slowly rising over time
Ah, it's a good thing that I looked at this thread. I KNEW having an invisible skin that runs in the background would eventually cause some problems... (I'm the author of the suite in question).
Before I continue, it's important to mention that everything I'm going to say will be based off a newer version of the suite than what you have. You have v1.3.1, I'm running v1.4.0-rc.3 (the most recent beta release). It would be a good idea for you to get this version, which you can do by clicking here, or by clicking the "Opt-in to development testing" toggle in the global settings skin.
There are significant differences between the .INI you provided and the most recent revision of it, so here is the updated code:
Anyway, you are actually seeing two separate skins. The one you provided the .INI file for is the "Setup" skin, which runs in the background constantly. It periodically checks for updates as well as creates settings backups for use when you update ModernGadgets. The second one that has the "load gadgets" toggles is the Gadget Manager.
Here is ModernGadgets\Config\GadgetManager and ModernGadgets\Config\Setup side-by-side: As for why it is invisible, when the skin loads, it is invisible by default. It only shows itself for two reasons: If you have just loaded it for the first time (loaded=0, which causes it to show the "import settings backup" prompt), or if there is an update available, in which case it'll show something like this: As for the rising CPU usage, there are two possible things that could be causing it: The settings backups or the update checking. The settings backups are performed with the following measures and script:
And the update check is performed with the following measures and script:
I honestly don't know how these things could be causing the rising CPU usage with this skin, but I hope this info can help. If you need clarifications or more info, I'll do my best to accommodate.
If it helps, you can find the complete source code of the suite here.
Before I continue, it's important to mention that everything I'm going to say will be based off a newer version of the suite than what you have. You have v1.3.1, I'm running v1.4.0-rc.3 (the most recent beta release). It would be a good idea for you to get this version, which you can do by clicking here, or by clicking the "Opt-in to development testing" toggle in the global settings skin.
There are significant differences between the .INI you provided and the most recent revision of it, so here is the updated code:
Code: Select all
[Rainmeter]
MiddleMouseDownAction=[!Refresh]
Group=ModernGadgets | ModernGadgetsSetup
; LeftMouseUpAction=[!CommandMeasure MeasureSettingsBackupScript "ImportBackup()"]
; RightMouseUpAction=[!ShowMeterGroup Essentials][!ShowMeterGroup ImportBackupPrompt][!Redraw]
; OnRefreshAction=[!CommandMeasure MeasureUpdateCheckerScript "CheckForUpdate('1.1.2', '1.2.0')"]
; OnRefreshAction=[!ShowMeterGroup Essentials][!ShowMeterGroup ImportBackupPrompt][!SetOption BackgroundHeightAdjuster Y R][!UpdateMeter BackgroundHeightAdjuster][!UpdateMeterGroup Essentials][!Redraw][!ShowFade]
; OnRefreshAction=[!CommandMeasure MeasureSettingsBackupScript "CheckForBackup()"]
; OnRefreshAction=[!Move "((#SCREENAREAWIDTH# / 2) - (#CURRENTCONFIGWIDTH# / 2))" "((#SCREENAREAHEIGHT# / 2) - (#CURRENTCONFIGHEIGHT# / 2))"]
AccurateText=1
[Metadata]
Name=Setup
Author=raiguard
Information=Background skin for ModernGadgets, manages settings backups and update checking.
License=Creative Commons Attribution-NonCommercial-ShareAlike 3.0
Version=1.4.0-rc.3
; ========= Variables and Styles =========
[Variables]
@includeStyleSheet=#@#StyleSheet.inc
@includeGlobalSettings=#@#Settings\GlobalSettings.inc
bgWidth=250
bgHeight=149
loaded=1
contentMarginAbs=4
updateCheckRate=30
webParserUpdateCheckRate=(#updateCheckRate# * 60)
; ==================================================
; MEASURES
; ==================================================
[MeasureSettingsBackupScript]
Measure=Script
ScriptFile=#@#Scripts\SettingsBackups.lua
[MeasureUpdateCheckerScript]
Measure=Script
ScriptFile=#@#Scripts\UpdateChecker.lua
CheckForPrereleases=#checkForPrereleases#
;UpToDateAction=[!Log "ModernGadgets is up-to-date" "Notice"]
;DevAction=[!Log "Dev version" "Notice"]
UpdateAvailableAction=[!Log "An update is available!" "Notice"][!CommandMeasure MeasureCreateBackup "Run"][!Hide][!HideMeterGroup ImportBackupPrompt][!UpdateMeterGroup UpdateAvailable][!ShowMeterGroup UpdateAvailable][!UpdateMeter BackgroundHeightAdjuster][!UpdateMeterGroup Essentials][!UpdateMeter Background][!ShowMeterGroup Essentials][!Redraw][!EnableMeasure MeasureMove][!UpdateMeasure MeasureMove]
ParsingErrorAction=[!Log "Error parsing version numbers" "Error"]
[MeasureMove]
Measure=Calc
Formula=1
IfCondition=1
IfTrueAction=[!Move "((#SCREENAREAWIDTH# / 2) - (#CURRENTCONFIGWIDTH# / 2))" "((#SCREENAREAHEIGHT# / 2) - (#CURRENTCONFIGHEIGHT# / 2))"][!ShowFade][!DisableMeasure MeasureMove]
DynamicVariables=1
Disabled=1
[MeasureUpdateCheck]
Measure=WebParser
URL=https://api.github.com/repos/raiguard/ModernGadgets/releases
; URL=file://#@#TestRemote.txt
RegExp=(?siU)^(.*)$
StringIndex=1
UpdateRate=#webParserUpdateCheckRate#
OnConnectErrorAction=[!Log "Couldn't connect to update server" "Error"]
FinishAction=[!CommandMeasure MeasureUpdateCheckerScript "CheckForUpdate('#mgVersion#', 'MeasureUpdateCheck')"]
DynamicVariables=1
Disabled=(#notifyUpdates# = 0)
[MeasureCreateBackup]
Measure=Plugin
Plugin=RunCommand
Parameter=xcopy /s "#@#Settings" "#SETTINGSPATH#ModernGadgetsSettings" /Y
FinishAction=[!Log "Created settings backup" "Notice"]
IfCondition=(#loaded# = 0)
IfTrueAction=[!CommandMeasure MeasureCopyDefaults "Run"][!WriteKeyValue Variables loaded 1][!CommandMeasure MeasureSettingsBackupScript "CheckForBackup()"]
[MeasureSettingsBackup]
Measure=Calc
IfCondition=(#autoBackups# = 1)
IfTrueAction=[!CommandMeasure MeasureCreateBackup "Run"][!DisableMeasure MeasureSettingsBackup]
IfFalseAction=[!DisableMeasure MeasureSettingsBackup]
Disabled=1
DynamicVariables=1
[MeasureCopyDefaults]
Measure=Plugin
Plugin=RunCommand
Parameter=xcopy /s "#@#Settings" "#SETTINGSPATH#ModernGadgetsSettings\Defaults" /Y
FinishAction=[!Log "Copied defaults" "Notice"]
[MeasureDownloadUpdate]
Measure=WebParser
URL=[&MeasureUpdateCheckerScript:GetReleaseInfo('downloadUrl')]
Download=1
OnConnectErrorAction=[!CommandMeasure MeasureDownloading "Stop 1"][!HideMeter MeterDownloadingUpdate][!ShowMeter MeterDownloadUpdateButtonLabel][!SetOption MeterDownloadUpdateButtonLabel Text "ERROR!"][!UpdateMeter MeterDownloadUpdateButtonLabel][!Redraw]
OnDownloadErrorAction=[!CommandMeasure MeasureDownloading "Stop 1"][!HideMeter MeterDownloadingUpdate][!ShowMeter MeterDownloadUpdateButtonLabel][!SetOption MeterDownloadUpdateButtonLabel Text "ERROR!"][!UpdateMeter MeterDownloadUpdateButtonLabel][!Redraw]
FinishAction=[!CommandMeasure MeasureDownloading "Stop 1"][!HideMeter MeterDownloadingUpdate][!ShowMeter MeterDownloadUpdateButtonLabel][!SetOption MeterDownloadUpdateButtonLabel Text "Installing..."][!UpdateMeter MeterDownloadUpdateButtonLabel][!Redraw]["[MeasureDownloadUpdate]"]
DynamicVariables=1
Disabled=1
[MeasureDownloading]
Measure=Plugin
Plugin=ActionTimer
ActionList1=ActionDownloading0 | Wait 500 | ActionDownloading1 | Wait 500 | ActionDownloading2 | Wait 500 | ActionDownloading3 | Wait 500 | DoOver
ActionDownloading0=[!SetOption MeterDownloadingUpdate Text "Downloading"][!UpdateMeter MeterDownloadingUpdate][!Redraw]
ActionDownloading1=[!SetOption MeterDownloadingUpdate Text "Downloading."][!UpdateMeter MeterDownloadingUpdate][!Redraw]
ActionDownloading2=[!SetOption MeterDownloadingUpdate Text "Downloading.."][!UpdateMeter MeterDownloadingUpdate][!Redraw]
ActionDownloading3=[!SetOption MeterDownloadingUpdate Text "Downloading..."][!UpdateMeter MeterDownloadingUpdate][!Redraw]
DoOver=[!CommandMeasure MeasureDownloading "Execute 1"]
; ==================================================
; METERS
; ==================================================
[Background]
Meter=Image
MeterStyle=StyleBackground
Group=Essentials
Hidden=1
[CloseButton]
Meter=Image
MeterStyle=StyleCloseButton
LeftMouseUpAction=[!HideFade]
Hidden=1
Group=UpdateAvailable
[UpdateAvailableLabelString]
Meter=String
MeterStyle=StyleString
FontSize=14
StringAlign=Center
X=#contentMarginCenter#
Y=20
Text=Update available!
Hidden=1
Group=UpdateAvailable
[ChangelogString]
Meter=String
MeterStyle=StyleString | StyleStringParagraph
FontSize=8
FontColor=180,180,180
X=(#contentMargin# + 4)
Text=[&MeasureUpdateCheckerScript:GetReleaseInfo('changelog')]
DynamicVariables=1
Group=UpdateAvailable
Hidden=1
[MeterDownloadUpdateButtonLabel]
Meter=String
MeterStyle=StyleString | StyleStringArrowButtonLabel
Text=Download
Hidden=1
Group=UpdateAvailable
DynamicVariables=1
[DownloadUpdateButton]
Meter=Image
MeterStyle=StyleArrowButton
MouseOverAction=[!SetOption DownloadUpdateButton ImageTint "#colorButtonPress#"][!UpdateMeter DownloadUpdateButton][!Redraw]
MouseLeaveAction=[!SetOption DownloadUpdateButton ImageTint ""][!UpdateMeter DownloadUpdateButton][!Redraw]
LeftMouseUpAction=[!HideMeter MeterDownloadUpdateButtonLabel][!ShowMeter MeterDownloadingUpdate][!CommandMeasure MeasureDownloading "Execute 1"][!EnableMeasure MeasureDownloadUpdate][!UpdateMeasure MeasureDownloadUpdate]
Hidden=1
Group=UpdateAvailable
DynamicVariables=1
[MeterDownloadingUpdate]
Meter=String
MeterStyle=StyleString | StyleStringArrowButtonLabel
StringAlign=Left
X=-90r
Y=r
Text=Downloading
Hidden=1
[NeverShowAgainString]
Meter=String
MeterStyle=StyleString
FontColor=#colorAccent#
X=#contentMargin# + 4
Y=4r
Text=Never show this again
MouseOverAction=[!SetOption NeverShowAgainString FontColor "#colorButtonPress#"][!UpdateMeter NeverShowAgainString][!Redraw]
MouseLeaveAction=[!SetOption NeverShowAgainString FontColor "#colorAccent#"][!UpdateMeter NeverShowAgainString][!Redraw]
LeftMouseUpAction=[!WriteKeyValue Variables notifyUpdates 0 "#globalSettingsPath#"][!DeactivateConfig]
ToolTipText=Update notifications will be turned off and this skin will unload
Hidden=1
Group=UpdateAvailable
[ImportBackupLabelString]
Meter=String
MeterStyle=StyleString
FontSize=14
StringAlign=Center
X=#contentMarginCenter#
Y=20
Text=Import settings backup?
Hidden=1
Group=ImportBackupPrompt
[ImportBackupInfoString]
Meter=String
MeterStyle=StyleString | StyleStringInfo
FontSize=10
Y=5R
W=(#contentWidth# - 20)
ClipString=2
Text=This will restore your customizations and update the gadgets to reflect them#CRLF##CRLF#NOTICE: THIS UPDATE CHANGES THE HWiNFO SETTINGS FORMAT. EVEN IF YOU IMPORT THE BACKUP, YOU WILL STILL NEED TO RECONFIGURE YOUR HWiNFO IDs!
InlinePattern=NOTICE.*
InlineSetting=Color | #colorButtonPress#
Hidden=1
Group=ImportBackupPrompt
[ImportBackupYesLabelString]
Meter=String
MeterStyle=StyleString | StyleStringArrowButtonLabel
Y=5R
Text=Yes
Text=Import settings backup?
Hidden=1
Group=ImportBackupPrompt
[ImportBackupYesButton]
Meter=Image
MeterStyle=StyleArrowButton
MouseOverAction=[!SetOption ImportBackupYesButton ImageTint "#colorButtonPress#"][!UpdateMeter ImportBackupYesButton][!Redraw]
MouseLeaveAction=[!SetOption ImportBackupYesButton ImageTint "#colorAccent#"][!UpdateMeter ImportBackupYesButton][!Redraw]
LeftMouseUpAction=[!CommandMeasure MeasureSettingsBackupScript "ImportBackup()"][!HideFade][!HideMeterGroup ImportBackupPrompt][!ActivateConfig "ModernGadgets\Config\GadgetManager" "Config.ini"]
Hidden=1
Group=ImportBackupPrompt
[ImportBackupNoLabelString]
Meter=String
MeterStyle=StyleString | StyleStringArrowButtonLabel
Text=No
Text=Import settings backup?
Hidden=1
Group=ImportBackupPrompt
[ImportBackupNoButton]
Meter=Image
MeterStyle=StyleArrowButton
MouseOverAction=[!SetOption ImportBackupNoButton ImageTint "#colorButtonPress#"][!UpdateMeter ImportBackupNoButton][!Redraw]
MouseLeaveAction=[!SetOption ImportBackupNoButton ImageTint "#colorAccent#"][!UpdateMeter ImportBackupNoButton][!Redraw]
LeftMouseUpAction=[!HideFade][!HideMeterGroup ImportBackupPrompt][!ActivateConfig "ModernGadgets\Config\GadgetManager" "Config.ini"]
Hidden=1
Group=ImportBackupPrompt
[BackgroundHeightAdjuster]
Meter=Image
Y=([NeverShowAgainString:Y] + [NeverShowAgainString:H])
DynamicVariables=1
Group=UpdateAvailable
[BackgroundHeight]
Meter=Image
MeterStyle=StyleackgroundHeight
Y=(#contentMarginAbs# + #bgOffset# + 3)R
Group=Essentials
Here is ModernGadgets\Config\GadgetManager and ModernGadgets\Config\Setup side-by-side: As for why it is invisible, when the skin loads, it is invisible by default. It only shows itself for two reasons: If you have just loaded it for the first time (loaded=0, which causes it to show the "import settings backup" prompt), or if there is an update available, in which case it'll show something like this: As for the rising CPU usage, there are two possible things that could be causing it: The settings backups or the update checking. The settings backups are performed with the following measures and script:
Code: Select all
[MeasureSettingsBackupScript]
Measure=Script
ScriptFile=#@#Scripts\SettingsBackups.lua
[MeasureCreateBackup]
Measure=Plugin
Plugin=RunCommand
Parameter=xcopy /s "#@#Settings" "#SETTINGSPATH#ModernGadgetsSettings" /Y
FinishAction=[!Log "Created settings backup" "Notice"]
IfCondition=(#loaded# = 0)
IfTrueAction=[!CommandMeasure MeasureCopyDefaults "Run"][!WriteKeyValue Variables loaded 1][!CommandMeasure MeasureSettingsBackupScript "CheckForBackup()"]
Code: Select all
-- MODERNGADGETS SETTINGS BACKUP SCRIPT
--
-- This script makes backups of the settings files every two hours, which
-- prevents them from being lost when updating the suite.
debug = false
function Initialize()
dofile(SKIN:GetVariable('scriptPath') .. 'Utilities.lua')
fileNames = { 'GlobalSettings.inc',
'CpuSettings.inc',
'NetworkSettings.inc',
'GpuSettings.inc',
'DisksSettings.inc',
'ProcessSettings.inc',
'ChronometerSettings.inc',
'GPU Variants\\GpuSettings1.inc',
'GPU Variants\\GpuSettings2.inc',
'GPU Variants\\GpuSettings3.inc' }
backupsPath = SKIN:GetVariable('SETTINGSPATH') .. 'ModernGadgetsSettings\\'
filesPath = SKIN:GetVariable('@') .. 'Settings\\'
cpuMeterPath = SKIN:GetVariable('cpuMeterPath')
networkMeterPath = SKIN:GetVariable('networkMeterPath')
gpuMeterPath = SKIN:GetVariable('gpuMeterPathBase')
disksMeterPath = SKIN:GetVariable('disksMeterPath')
end
function Update() end
function ImportBackup()
for i=1, 10 do
local bTable = ReadIni(backupsPath .. fileNames[i])
local sTable = ReadIni(filesPath .. fileNames[i])
CrossCheck(bTable, sTable, filesPath .. fileNames[i])
end
SKIN:Bang('!RefreshGroup', 'MgImportRefresh')
LogHelper('Imported settings backup', 'Notice')
end
function CrossCheck(bTable, sTable, filePath)
for i,v in pairs(bTable) do
if type(v) == 'table' then
for a,b in pairs(v) do
if sTable[i][a] then
SKIN:Bang('!WriteKeyValue', i, a, b, filePath)
else
LogHelper('Key \'' .. a .. '\' does not exist in local', 'Debug')
end
end
end
end
end
function CheckForBackup()
local file = io.open(backupsPath .. fileNames[1])
if file == nil then
SKIN:Bang('!ActivateConfig', 'ModernGadgets\\Config\\GadgetManager', 'Config.ini')
SKIN:Bang('!CommandMeasure', 'MeasureCreateBackup', 'Run')
else
SKIN:Bang('!Hide')
SKIN:Bang('!ShowMeterGroup', 'Essentials')
SKIN:Bang('!ShowMeterGroup', 'ImportBackupPrompt')
SKIN:Bang('!SetOption', 'BackgroundHeightAdjuster', 'Y', 'R')
SKIN:Bang('!UpdateMeter', 'BackgroundHeightAdjuster')
SKIN:Bang('!UpdateMeterGroup', 'Essentials')
SKIN:Bang('!Redraw')
SKIN:Bang('!EnableMeasure', 'MeasureMove')
SKIN:Bang('!UpdateMeasure', 'MeasureMove')
file:close()
end
end
-- parses a INI formatted text file into a 'Table[Section][Key] = Value' table
function ReadIni(inputfile)
local file = assert(io.open(inputfile, 'r'), 'Unable to open ' .. inputfile)
local tbl, num, section = {}, 0
for line in file:lines() do
num = num + 1
if not line:match('^%s-;') then
local key, command = line:match('^([^=]+)=(.+)')
if line:match('^%s-%[.+') then
section = line:match('^%s-%[([^%]]+)')
if section == '' or not section then
section = nil
LogHelper('Empty section name found in ' .. inputfile, 'Debug')
end
if not tbl[section] then tbl[section] = {} end
elseif key and command and section then
tbl[section][key:match('^%s*(%S*)%s*$')] = command:match('^%s*(.-)%s*$'):gsub('#(.-)#', '#\*%1\*#')
elseif #line > 0 and section and not key or command then
LogHelper(num .. ': Invalid property or value.', 'Debug')
end
end
end
file:close()
if not section then LogHelper('No sections found in ' .. inputfile, 'Debug') end
return tbl
end
Code: Select all
[MeasureUpdateCheckerScript]
Measure=Script
ScriptFile=#@#Scripts\UpdateChecker.lua
CheckForPrereleases=#checkForPrereleases#
;UpToDateAction=[!Log "ModernGadgets is up-to-date" "Notice"]
;DevAction=[!Log "Dev version" "Notice"]
UpdateAvailableAction=[!Log "An update is available!" "Notice"][!CommandMeasure MeasureCreateBackup "Run"][!Hide][!HideMeterGroup ImportBackupPrompt][!UpdateMeterGroup UpdateAvailable][!ShowMeterGroup UpdateAvailable][!UpdateMeter BackgroundHeightAdjuster][!UpdateMeterGroup Essentials][!UpdateMeter Background][!ShowMeterGroup Essentials][!Redraw][!EnableMeasure MeasureMove][!UpdateMeasure MeasureMove]
ParsingErrorAction=[!Log "Error parsing version numbers" "Error"]
[MeasureMove]
Measure=Calc
Formula=1
IfCondition=1
IfTrueAction=[!Move "((#SCREENAREAWIDTH# / 2) - (#CURRENTCONFIGWIDTH# / 2))" "((#SCREENAREAHEIGHT# / 2) - (#CURRENTCONFIGHEIGHT# / 2))"][!ShowFade][!DisableMeasure MeasureMove]
DynamicVariables=1
Disabled=1
[MeasureUpdateCheck]
Measure=WebParser
; URL=https://api.github.com/repos/raiguard/ModernGadgets/releases
URL=file://#CURRENTPATH#TestRemote.txt
RegExp=(?siU)^(.*)$
StringIndex=1
UpdateRate=#webParserUpdateCheckRate#
OnConnectErrorAction=[!Log "Couldn't connect to update server" "Error"]
FinishAction=[!CommandMeasure MeasureUpdateCheckerScript "CheckForUpdate('#mgVersion#', 'MeasureUpdateCheck')"]
DynamicVariables=1
Disabled=(#notifyUpdates# = 0)
Code: Select all
--[[
--------------------------------------------------
Update Checker for Rainmeter
v6.1.0
By raiguard
Implements 'semver.lua' by kikito (https://github.com/kikito/semver.lua)
Implements 'JSON.lua' by rxi (https://github.com/rxi/json.lua)
--------------------------------------------------
Release Notes:
v6.1.0 - 2018-7-4
- Added 'RawChangelog' option
v6.0.0 - 2018-7-2
- Switched to use GitHub REST v3 API, rather than a customized INI file
v5.1.0 - 2018-6-21
- Switched to using the WebParser measure output rather than a downloaded file
for the ReadINI function
v5.0.0 - 2017-12-20
- Removed hard-coded actions and replaced with arguments in the script measure
- Switched to using INI format for the remote version data
- Added 'GetIniValue' function for retrieving other information from remote
v4.0.0 - 2016-11-18
- Implemented "semver.lua" for more robust comparisons
v3.0.0 - 2016-11-14
- Added support for update checking on development versions
v2.1.0 - 2016-11-14
- Fixed oversight where if the user is on a development version for an
outdated release, it would not return UpdateAvailable()
- Added 'ParsingError' return
v2.0.0 - 2016-8-4
- Removed dependancy on an output meter in favor of hard-coded actions, added
more documentation
v1.0.1 - 2016-7-1
- Optimized gmatch function, more debug functionality
v1.0.0 - 2016-1-25
- Initial release
--------------------------------------------------
This script compares two semver-formatted version strings and compares them,
returning whether the current version is outdated, up-to-date, or a development
version. By default, it uses the GitHub REST API to download release information,
automatically extracting the most recent release from the specified repository.
However, you do not need to use this if you have another method for retrieving
the most recently released version.
Please keep in mind that version strings must be formatted using the Semantic
Versioning 2.0.0 format. See http://semver.org/ for additional information.
--------------------------------------------------
INSTRUCTIONS FOR USE:
[MeasureUpdateCheckerScript]
Measure=Script
Script=#@#Scripts\UpdateChecker.lua
CheckForPrereleases=#checkForPrereleases#
UpToDateAction=[!ShowMeter "UpToDateString"]
DevAction=[!ShowMeter "DevString"]
UpdateAvailableAction=[!ShowMeter "UpdateAvailableString"]
ParsingErrorAction=[!ShowMeter "ParsingErrorString"]
This is an example of the script measure you will use to invoke this script.
The 'CheckForPrereleases' defines whether the update checker will compare
with the most recent full release, or the most recent release whatsoever.
Each action option is a series of bangs to execute when that outcome is
reached by the comparison function.
[MeasureUpdateCheck]
Measure=WebParser
URL=#webParserUrl#
RegExp=(?siU)^(.*)$
StringIndex=1
UpdateRate=#updateCheckRate#
OnConnectErrorAction=[!Log "Couldn't connect to update server" "Error"]
FinishAction=[!CommandMeasure MeasureUpdateCheckerScript "CheckForUpdate('#version#', 'MeasureUpdateCheck')"]
DynamicVariables=1
This is an example of the webparser measure used to download the information.
The important thing to note here is the last argument on the 'FinishAction'
line. This must be the name of the WebParser measure, whatever that may
be. This allows the script to actually retrieve the string that was downloaded,
which lets the update check actually take place.
The script retrieves the raw JSON data from the GitHub API, then uses a JSON
parser function to convert it into a LUA table. From there, the script extracts
data for the most recent full release, and the most recent release regardless
of whether or not it is a prerelease. Which release is compared to and provides
the release information is determined by the 'CheckForPrereleases' option in the
script measure.
There are four values for each release that you can retrieve for displaying in
your skin. Each value is retrieved using
[&MeasureUpdateCheckerScript:GetReleaseInfo('key')]. Replace key with one of the
following options:
'name' - returns the tag version of the release
'date' - returns the published date of the release
'changelog' - returns the release's changelog, with the release version and
published date added to the beginning
'downloadUrl' - returns the URL that can be used to download the .RMSKIN
attached to the release
Please note that any meter that extracts information from the script in this way
will need 'DynamicVariables=1' set in order to function properly.
By default, the changelog will include the release's tag version and published
date attached to the beginning of the string. If you wish to disable this, add
'RawChangelog=1' to the script measure.
--------------------------------------------------
]]--
debug = false
function Initialize()
upToDateAction = SELF:GetOption('UpToDateAction')
updateAvailableAction = SELF:GetOption('UpdateAvailableAction')
parsingErrorAction = SELF:GetOption('ParsingErrorAction')
devAction = SELF:GetOption('DevAction')
rawChangelog = tonumber(SELF:GetOption('RawChangelog', '0'))
checkForPrereleases = tonumber(SELF:GetOption('CheckForPrereleases', '1'))
if devAction == '' or devAction == nil then devAction = upToDateAction end
printIndent = ' '
releases = {}
end
function Update() end
function CheckForUpdate(cVersion, measureName)
showPrereleases = tonumber(SELF:GetOption('ShowPrereleases', 1))
apiJson = json.decode(SKIN:GetMeasure(measureName or 'MeasureUpdateCheck'):GetStringValue())
releases = AssembleReleaseInfo(apiJson)
Compare(cVersion, releases[checkForPrereleases + 1]['name'])
end
-- compares two semver-formatted version strings
function Compare(cVersion, rVersion)
cVersion = v(cVersion)
rVersion = v(rVersion)
if cVersion == rVersion then
LogHelper('Up-to-date', 'Debug')
SKIN:Bang(upToDateAction)
elseif cVersion > rVersion then
LogHelper('Development version', 'Debug')
SKIN:Bang(devAction)
elseif cVersion < rVersion then
LogHelper('Update available', 'Debug')
SKIN:Bang(updateAvailableAction)
else
LogHelper('Parsing error', 'Debug')
SKIN:Bang(parsingErrorAction)
end
end
function GetReleaseInfo(key)
return releases[checkForPrereleases + 1] and releases[checkForPrereleases + 1][key] or '---'
end
function AssembleReleaseInfo(jsonTable)
local releases = {}
local i = 0
local k = 0
while i == 0 do
k = k + 1
if jsonTable[k]['prerelease'] == false then
i = 1
releases[1] = {}
releases[1]['name'] = jsonTable[k]['tag_name']:gsub('v', '')
releases[1]['date'] = jsonTable[k]['published_at']:gsub('(.*)T(.*)', '%1')
releases[1]['changelog'] = (rawChangelog == 0 and 'v' .. releases[1]['name'] .. ' - ' .. releases[1]['date'] .. '\n' or '') .. jsonTable[k]['body']:gsub('\r\n', '\n')
releases[1]['downloadUrl'] = jsonTable[k]['assets'][1]['browser_download_url']
end
end
releases[2] = {}
releases[2]['name'] = jsonTable[1]['tag_name']:gsub('v', '')
releases[2]['date'] = jsonTable[1]['published_at']:gsub('(.*)T(.*)', '%1')
releases[2]['changelog'] = (rawChangelog == 0 and 'v' .. releases[2]['name'] .. ' - ' .. releases[2]['date'] .. '\n' or '') .. jsonTable[1]['body']:gsub('\r\n', '\n')
releases[2]['downloadUrl'] = jsonTable[1]['assets'][1]['browser_download_url']
return releases
end
-- function to make logging messages less cluttered
function LogHelper(message, type)
if type == nil then type = 'Debug' end
if debug == true then
SKIN:Bang("!Log", message, type)
elseif type ~= 'Debug' then
SKIN:Bang("!Log", message, type)
end
end
--[[
--------------------------------------------------
SEMVER.LUA
By kitito
MIT LICENSE
Copyright (c) 2015 Enrique García Cota
Permission is hereby granted, free of charge, to any person obtaining a
copy of tother software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and tother permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------
]]--
local function checkPositiveInteger(number, name)
assert(number >= 0, name .. ' must be a valid positive number')
assert(math.floor(number) == number, name .. ' must be an integer')
end
local function present(value)
return value and value ~= ''
end
-- splitByDot("a.bbc.d") == {"a", "bbc", "d"}
local function splitByDot(str)
str = str or ""
local t, count = {}, 0
str:gsub("([^%.]+)", function(c)
count = count + 1
t[count] = c
end)
return t
end
local function parsePrereleaseAndBuildWithSign(str)
local prereleaseWithSign, buildWithSign = str:match("^(-[^+]+)(+.+)$")
if not (prereleaseWithSign and buildWithSign) then
prereleaseWithSign = str:match("^(-.+)$")
buildWithSign = str:match("^(+.+)$")
end
assert(prereleaseWithSign or buildWithSign, ("The parameter %q must begin with + or - to denote a prerelease or a build"):format(str))
return prereleaseWithSign, buildWithSign
end
local function parsePrerelease(prereleaseWithSign)
if prereleaseWithSign then
local prerelease = prereleaseWithSign:match("^-(%w[%.%w-]*)$")
assert(prerelease, ("The prerelease %q is not a slash followed by alphanumerics, dots and slashes"):format(prereleaseWithSign))
return prerelease
end
end
local function parseBuild(buildWithSign)
if buildWithSign then
local build = buildWithSign:match("^%+(%w[%.%w-]*)$")
assert(build, ("The build %q is not a + sign followed by alphanumerics, dots and slashes"):format(buildWithSign))
return build
end
end
local function parsePrereleaseAndBuild(str)
if not present(str) then return nil, nil end
local prereleaseWithSign, buildWithSign = parsePrereleaseAndBuildWithSign(str)
local prerelease = parsePrerelease(prereleaseWithSign)
local build = parseBuild(buildWithSign)
return prerelease, build
end
local function parseVersion(str)
local sMajor, sMinor, sPatch, sPrereleaseAndBuild = str:match("^(%d+)%.?(%d*)%.?(%d*)(.-)$")
assert(type(sMajor) == 'string', ("Could not extract version number(s) from %q"):format(str))
local major, minor, patch = tonumber(sMajor), tonumber(sMinor), tonumber(sPatch)
local prerelease, build = parsePrereleaseAndBuild(sPrereleaseAndBuild)
return major, minor, patch, prerelease, build
end
-- return 0 if a == b, -1 if a < b, and 1 if a > b
local function compare(a,b)
return a == b and 0 or a < b and -1 or 1
end
local function compareIds(myId, otherId)
if myId == otherId then return 0
elseif not myId then return -1
elseif not otherId then return 1
end
local selfNumber, otherNumber = tonumber(myId), tonumber(otherId)
if selfNumber and otherNumber then -- numerical comparison
return compare(selfNumber, otherNumber)
-- numericals are always smaller than alphanums
elseif selfNumber then
return -1
elseif otherNumber then
return 1
else
return compare(myId, otherId) -- alphanumerical comparison
end
end
local function smallerIdList(myIds, otherIds)
local myLength = #myIds
local comparison
for i=1, myLength do
comparison = compareIds(myIds[i], otherIds[i])
if comparison ~= 0 then
return comparison == -1
end
-- if comparison == 0, continue loop
end
return myLength < #otherIds
end
local function smallerPrerelease(mine, other)
if mine == other or not mine then return false
elseif not other then return true
end
return smallerIdList(splitByDot(mine), splitByDot(other))
end
local methods = {}
function methods:nextMajor()
return semver(self.major + 1, 0, 0)
end
function methods:nextMinor()
return semver(self.major, self.minor + 1, 0)
end
function methods:nextPatch()
return semver(self.major, self.minor, self.patch + 1)
end
local mt = { __index = methods }
function mt:__eq(other)
return self.major == other.major and
self.minor == other.minor and
self.patch == other.patch and
self.prerelease == other.prerelease
-- notice that build is ignored for precedence in semver 2.0.0
end
function mt:__lt(other)
if self.major ~= other.major then return self.major < other.major end
if self.minor ~= other.minor then return self.minor < other.minor end
if self.patch ~= other.patch then return self.patch < other.patch end
return smallerPrerelease(self.prerelease, other.prerelease)
-- notice that build is ignored for precedence in semver 2.0.0
end
-- This works like the "pessimisstic operator" in Rubygems.
-- if a and b are versions, a ^ b means "b is backwards-compatible with a"
-- in other words, "it's safe to upgrade from a to b"
function mt:__pow(other)
if self.major == 0 then
return self == other
end
return self.major == other.major and
self.minor <= other.minor
end
function mt:__tostring()
local buffer = { ("%d.%d.%d"):format(self.major, self.minor, self.patch) }
if self.prerelease then table.insert(buffer, "-" .. self.prerelease) end
if self.build then table.insert(buffer, "+" .. self.build) end
return table.concat(buffer)
end
function v(major, minor, patch, prerelease, build)
assert(major, "At least one parameter is needed")
if type(major) == 'string' then
major,minor,patch,prerelease,build = parseVersion(major)
end
patch = patch or 0
minor = minor or 0
checkPositiveInteger(major, "major")
checkPositiveInteger(minor, "minor")
checkPositiveInteger(patch, "patch")
local result = {major=major, minor=minor, patch=patch, prerelease=prerelease, build=build}
return setmetatable(result, mt)
end
--
-- json.lua
--
-- Copyright (c) 2018 rxi
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy of
-- this software and associated documentation files (the "Software"), to deal in
-- the Software without restriction, including without limitation the rights to
-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-- of the Software, and to permit persons to whom the Software is furnished to do
-- so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in all
-- copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-- SOFTWARE.
--
json = { _version = "0.1.1" }
-------------------------------------------------------------------------------
-- Encode
-------------------------------------------------------------------------------
local encode
local escape_char_map = {
[ "\\" ] = "\\\\",
[ "\"" ] = "\\\"",
[ "\b" ] = "\\b",
[ "\f" ] = "\\f",
[ "\n" ] = "\\n",
[ "\r" ] = "\\r",
[ "\t" ] = "\\t",
}
local escape_char_map_inv = { [ "\\/" ] = "/" }
for k, v in pairs(escape_char_map) do
escape_char_map_inv[v] = k
end
local function escape_char(c)
return escape_char_map[c] or string.format("\\u%04x", c:byte())
end
local function encode_nil(val)
return "null"
end
local function encode_table(val, stack)
local res = {}
stack = stack or {}
-- Circular reference?
if stack[val] then error("circular reference") end
stack[val] = true
if val[1] ~= nil or next(val) == nil then
-- Treat as array -- check keys are valid and it is not sparse
local n = 0
for k in pairs(val) do
if type(k) ~= "number" then
error("invalid table: mixed or invalid key types")
end
n = n + 1
end
if n ~= #val then
error("invalid table: sparse array")
end
-- Encode
for i, v in ipairs(val) do
table.insert(res, encode(v, stack))
end
stack[val] = nil
return "[" .. table.concat(res, ",") .. "]"
else
-- Treat as an object
for k, v in pairs(val) do
if type(k) ~= "string" then
error("invalid table: mixed or invalid key types")
end
table.insert(res, encode(k, stack) .. ":" .. encode(v, stack))
end
stack[val] = nil
return "{" .. table.concat(res, ",") .. "}"
end
end
local function encode_string(val)
return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"'
end
local function encode_number(val)
-- Check for NaN, -inf and inf
if val ~= val or val <= -math.huge or val >= math.huge then
error("unexpected number value '" .. tostring(val) .. "'")
end
return string.format("%.14g", val)
end
local type_func_map = {
[ "nil" ] = encode_nil,
[ "table" ] = encode_table,
[ "string" ] = encode_string,
[ "number" ] = encode_number,
[ "boolean" ] = tostring,
}
encode = function(val, stack)
local t = type(val)
local f = type_func_map[t]
if f then
return f(val, stack)
end
error("unexpected type '" .. t .. "'")
end
function json.encode(val)
return ( encode(val) )
end
-------------------------------------------------------------------------------
-- Decode
-------------------------------------------------------------------------------
local parse
local function create_set(...)
local res = {}
for i = 1, select("#", ...) do
res[ select(i, ...) ] = true
end
return res
end
local space_chars = create_set(" ", "\t", "\r", "\n")
local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",")
local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u")
local literals = create_set("true", "false", "null")
local literal_map = {
[ "true" ] = true,
[ "false" ] = false,
[ "null" ] = nil,
}
local function next_char(str, idx, set, negate)
for i = idx, #str do
if set[str:sub(i, i)] ~= negate then
return i
end
end
return #str + 1
end
local function decode_error(str, idx, msg)
local line_count = 1
local col_count = 1
for i = 1, idx - 1 do
col_count = col_count + 1
if str:sub(i, i) == "\n" then
line_count = line_count + 1
col_count = 1
end
end
error( string.format("%s at line %d col %d", msg, line_count, col_count) )
end
local function codepoint_to_utf8(n)
-- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa
local f = math.floor
if n <= 0x7f then
return string.char(n)
elseif n <= 0x7ff then
return string.char(f(n / 64) + 192, n % 64 + 128)
elseif n <= 0xffff then
return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128)
elseif n <= 0x10ffff then
return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128,
f(n % 4096 / 64) + 128, n % 64 + 128)
end
error( string.format("invalid unicode codepoint '%x'", n) )
end
local function parse_unicode_escape(s)
local n1 = tonumber( s:sub(3, 6), 16 )
local n2 = tonumber( s:sub(9, 12), 16 )
-- Surrogate pair?
if n2 then
return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000)
else
return codepoint_to_utf8(n1)
end
end
local function parse_string(str, i)
local has_unicode_escape = false
local has_surrogate_escape = false
local has_escape = false
local last
for j = i + 1, #str do
local x = str:byte(j)
if x < 32 then
decode_error(str, j, "control character in string")
end
if last == 92 then -- "\\" (escape char)
if x == 117 then -- "u" (unicode escape sequence)
local hex = str:sub(j + 1, j + 5)
if not hex:find("%x%x%x%x") then
decode_error(str, j, "invalid unicode escape in string")
end
if hex:find("^[dD][89aAbB]") then
has_surrogate_escape = true
else
has_unicode_escape = true
end
else
local c = string.char(x)
if not escape_chars[c] then
decode_error(str, j, "invalid escape char '" .. c .. "' in string")
end
has_escape = true
end
last = nil
elseif x == 34 then -- '"' (end of string)
local s = str:sub(i + 1, j - 1)
if has_surrogate_escape then
s = s:gsub("\\u[dD][89aAbB]..\\u....", parse_unicode_escape)
end
if has_unicode_escape then
s = s:gsub("\\u....", parse_unicode_escape)
end
if has_escape then
s = s:gsub("\\.", escape_char_map_inv)
end
return s, j + 1
else
last = x
end
end
decode_error(str, i, "expected closing quote for string")
end
local function parse_number(str, i)
local x = next_char(str, i, delim_chars)
local s = str:sub(i, x - 1)
local n = tonumber(s)
if not n then
decode_error(str, i, "invalid number '" .. s .. "'")
end
return n, x
end
local function parse_literal(str, i)
local x = next_char(str, i, delim_chars)
local word = str:sub(i, x - 1)
if not literals[word] then
decode_error(str, i, "invalid literal '" .. word .. "'")
end
return literal_map[word], x
end
local function parse_array(str, i)
local res = {}
local n = 1
i = i + 1
while 1 do
local x
i = next_char(str, i, space_chars, true)
-- Empty / end of array?
if str:sub(i, i) == "]" then
i = i + 1
break
end
-- Read token
x, i = parse(str, i)
res[n] = x
n = n + 1
-- Next token
i = next_char(str, i, space_chars, true)
local chr = str:sub(i, i)
i = i + 1
if chr == "]" then break end
if chr ~= "," then decode_error(str, i, "expected ']' or ','") end
end
return res, i
end
local function parse_object(str, i)
local res = {}
i = i + 1
while 1 do
local key, val
i = next_char(str, i, space_chars, true)
-- Empty / end of object?
if str:sub(i, i) == "}" then
i = i + 1
break
end
-- Read key
if str:sub(i, i) ~= '"' then
decode_error(str, i, "expected string for key")
end
key, i = parse(str, i)
-- Read ':' delimiter
i = next_char(str, i, space_chars, true)
if str:sub(i, i) ~= ":" then
decode_error(str, i, "expected ':' after key")
end
i = next_char(str, i + 1, space_chars, true)
-- Read value
val, i = parse(str, i)
-- Set
res[key] = val
-- Next token
i = next_char(str, i, space_chars, true)
local chr = str:sub(i, i)
i = i + 1
if chr == "}" then break end
if chr ~= "," then decode_error(str, i, "expected '}' or ','") end
end
return res, i
end
local char_func_map = {
[ '"' ] = parse_string,
[ "0" ] = parse_number,
[ "1" ] = parse_number,
[ "2" ] = parse_number,
[ "3" ] = parse_number,
[ "4" ] = parse_number,
[ "5" ] = parse_number,
[ "6" ] = parse_number,
[ "7" ] = parse_number,
[ "8" ] = parse_number,
[ "9" ] = parse_number,
[ "-" ] = parse_number,
[ "t" ] = parse_literal,
[ "f" ] = parse_literal,
[ "n" ] = parse_literal,
[ "[" ] = parse_array,
[ "{" ] = parse_object,
}
parse = function(str, idx)
local chr = str:sub(idx, idx)
local f = char_func_map[chr]
if f then
return f(str, idx)
end
decode_error(str, idx, "unexpected character '" .. chr .. "'")
end
function json.decode(str)
if type(str) ~= "string" then
error("expected argument of type string, got " .. type(str))
end
local res, idx = parse(str, next_char(str, 1, space_chars, true))
idx = next_char(str, idx, space_chars, true)
if idx <= #str then
decode_error(str, idx, "trailing garbage")
end
return res
end
return json
If it helps, you can find the complete source code of the suite here.
You do not have the required permissions to view the files attached to this post.
-
- Posts: 32
- Joined: March 10th, 2017, 1:47 am
Re: Rainmeter CPU util slowly rising over time
For what it is worth, I also see RainMeter CPU usage rising over time (I keep my PC on all the time and only reboot for Windows Updates monthly). I usually see it creeping up after 5 days or so of continuous use.
I do not run ModernGadgets / SysInfo
I do run SilverAzide's Gadgets, however, which are similar: CPU/GPU usage, Network, Disk, etc.
My suspicion is that it has something to do with the performance monitoring that these gadgets do. Along with RainMeter having high CPU usage, I also see WMIPrvSE.exe, which is the WMI service that is used for performance stats.
As mentioned by others, simply exiting RainMeter and restarting does not cure the CPU usage issue; it starts out higher (5-8%, but I've seen it at 15-30% before as well) than it does after a reboot (1-2% normally) in that scenario.
-shoek
I do not run ModernGadgets / SysInfo
I do run SilverAzide's Gadgets, however, which are similar: CPU/GPU usage, Network, Disk, etc.
My suspicion is that it has something to do with the performance monitoring that these gadgets do. Along with RainMeter having high CPU usage, I also see WMIPrvSE.exe, which is the WMI service that is used for performance stats.
As mentioned by others, simply exiting RainMeter and restarting does not cure the CPU usage issue; it starts out higher (5-8%, but I've seen it at 15-30% before as well) than it does after a reboot (1-2% normally) in that scenario.
-shoek