It is currently October 6th, 2022, 7:11 am

Rounded Screen Corners

General topics related to Rainmeter.
User avatar
Yincognito
Rainmeter Sage
Posts: 4806
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: Rounded Screen Corners

Post by Yincognito »

SubjunctiveQuaver wrote: April 19th, 2022, 9:38 am Ooh I've now tried that. Is there a way to get the DPI of each monitor (so I can adjust the corner radius accordingly?) Below are the improved snippets; they work for any screen as long as you set the right display monitor in settings!! (Just duplicate for each screen; is there a better way to do this?) Also the settings for click through/draggable etc. can be changed, but the !AutoSelectScreen is really important to keep as 1, which is the reason why it all works, and !ZPos is 2 to stay topmost.
Would also be good to update the metadata which right now is [...] but I'm not experienced with this stuff (not usually a coder lol, and I've lost track of who's contributed hahah)
Looks good to me, using auto selecting the screen and duplicating for the monitor you need - I don't think there's a better way of doing this, since manually specifying the number of the screen using @N requires changing the code accordingly, while this approach doesn't. Personally, I don't have multiple monitors, so I can't test, but if it works for you then it should work for anyone having multiple monitors.

Regarding the metadata, I guess adding istir (for the related idea of splitting one 'job' into more), myself (for adjusting it and implementing it) and yourself (for adding the multiple monitor part) should be enough, if you think so. I'm neutral on this, I don't mind either way, my intention was only to help in achieving the goal. ;-)

On the DPI thing, you probably didn't notice the EDIT in my previous reply here. While using such a Registry measure is trivial, the problem is figuring out how the names of those per monitor subfolders are constructed, since they might be different for each user (for me, the 1st "monitor" subfolfder is called BOE094A0_11_07E4_61^13B12C29BB6619B6E6B383B11D52D2EC, i.e. a construct involving other registry key names). This is further complicated by the fact that we don't know what DPI scaling values (expressed as percents or something humanly readable) correspond to Windows "codes" for each entry in the Start / Settings / System / Scale combobox list. That being said, the OP in this reddit wrote a PowerShell script that can be used in this case, with the proper adjustments, like:

Code: Select all

$activemonitorsregpath = 'HKCU:\Control Panel\Desktop\PerMonitorSettings';
$genericmonitorslist = Get-ChildItem 'HKLM:\System\CurrentControlSet\Control\GraphicsDrivers\ScaleFactors';
$dpicode = New-Object PSObject -Property @{'4294967295' = '100%'; '4294967294' = '100%'; '0' = '125%'; '1' = '150%'; '2' = '175%';};
$monitors = @(); $monitorindex = 0;
foreach ($genericmonitor in $genericmonitorslist)
{
  $regpath = $activemonitorsregpath + '\' + $genericmonitor.PsChildname;
  if (Test-Path -Path $regpath) {$dpivalue = (Get-ItemProperty -Path $regpath -Name 'DpiValue').'DpiValue'; $monitors += New-Object PSObject -Property @{'Index' = $monitorindex; 'Place' = $regpath; 'Scale' = $dpicode.$dpivalue}; $monitorindex++;}
}
$monitors | format-list;
which ouputs something like:
GetMonitorDPIScaling.jpg
This won't exactly be portable or distributable, since as I said, I have no clue where to get what each of those DPI scaling codes in the registry means in terms of actual percents or plain DPI, so I put them in a PSObject (more or less, an array) variable called $dpicode that one can edit according to what his combobox in Windows Settings displays (the above is what mine looks like). In the above script, all monitors and their index, place and scale properties are displayed, but one can easily display only the needed value, by using, for example, $monitors[0].Scale | format-list; instead of $monitors | format-list; in the last line, to print the first monitor / screen scaling percent, and so on.

After that, the script can be used in a RunCommand measure like this - sample code:

Code: Select all

[Variables]

[Rainmeter]
Update=1000
DynamicWindowSize=1
AccurateText=1
OnRefreshAction=[!CommandMeasure MonitorScale "Run"]

[MonitorScale]
Measure=Plugin
Plugin=RunCommand
Program=powershell
Parameter=-command $activemonitorsregpath = 'HKCU:\Control Panel\Desktop\PerMonitorSettings'; $genericmonitorslist = Get-ChildItem 'HKLM:\System\CurrentControlSet\Control\GraphicsDrivers\ScaleFactors'; $dpicode = New-Object PSObject -Property @{'4294967295' = '100%'; '4294967294' = '100%'; '0' = '125%'; '1' = '150%'; '2' = '175%';}; $monitors = @(); $monitorindex = 0; foreach ($genericmonitor in $genericmonitorslist) {$regpath = $activemonitorsregpath + '\' + $genericmonitor.PsChildname; if (Test-Path -Path $regpath) {$dpivalue = (Get-ItemProperty -Path $regpath -Name 'DpiValue').'DpiValue'; $monitors += New-Object PSObject -Property @{'Index' = $monitorindex; 'Place' = $regpath; 'Scale' = $dpicode.$dpivalue}; $monitorindex++;}} $monitors | format-list;
State=Hide
OutputType=ANSI
Timeout=10000
;RegExpSubstitute=1
;Substitute="":""
DynamicVariables=1

[Result]
Meter=String
FontColor=255,255,255,255
FontSize=10
AntiAlias=1
Text=[MonitorScale]
DynamicVariables=1
optionally adjusting the output to suit his needs in the (now commented via ;) Substitute option.

Eventually, an example applied to the current scenario would look like (your top skin used as a basis):

Code: Select all

[Variables]
CornerRadius=8
CornerColor=0,0,0

[Rainmeter]
Update=1000
DynamicWindowSize=1
OnRefreshAction=[!CommandMeasure MonitorScale "Run"][!AutoSelectScreen 1][!ClickThrough 1][!Draggable 0][!KeepOnScreen 1][!SnapEdges 1][!ZPos 2]

[MonitorScale]
Measure=Plugin
Plugin=RunCommand
Program=powershell
Parameter=-command $activemonitorsregpath = 'HKCU:\Control Panel\Desktop\PerMonitorSettings'; $genericmonitorslist = Get-ChildItem 'HKLM:\System\CurrentControlSet\Control\GraphicsDrivers\ScaleFactors'; $dpicode = New-Object PSObject -Property @{'4294967295' = '100%'; '4294967294' = '100%'; '0' = '125%'; '1' = '150%'; '2' = '175%';}; $monitors = @(); $monitorindex = 0; foreach ($genericmonitor in $genericmonitorslist) {$regpath = $activemonitorsregpath + '\' + $genericmonitor.PsChildname; if (Test-Path -Path $regpath) {$dpivalue = (Get-ItemProperty -Path $regpath -Name 'DpiValue').'DpiValue'; $monitors += New-Object PSObject -Property @{'Index' = $monitorindex; 'Place' = $regpath; 'Scale' = $dpicode.$dpivalue}; $monitorindex++;}} $monitors[0].Scale | format-list;
State=Hide
OutputType=ANSI
Timeout=10000
RegExpSubstitute=1
Substitute="%":""
FinishAction=[!SetVariable CornerRadius ([MonitorScale]/2)][!Update]
DynamicVariables=1

[MeterShapeCorners]
Meter=Shape
Shape=Rectangle 0,0,(#ScreenAreaWidth#),(#CornerRadius#) | Fill Color #CornerColor# | StrokeWidth 0
Shape2=Rectangle 0,0,(#ScreenAreaWidth#),(#CornerRadius#*2),#CornerRadius# | Fill Color 0,0,0,0
Shape3=Combine Shape | Exclude Shape2
OnUpdateAction=[!Move (#ScreenAreaX#) (#ScreenAreaY#)]
DynamicVariables=1
which will set the corner radius variable to the scaling percent value divided by 2 on refresh. This could further be adjusted to take the resolution (and its possible changes) into account by moving the [!CommandMeasure MonitorScale "Run"] in the meter's OnUpdateAction, increase the skin's update (or the meter's UpdateDivider) to a value that doesn't run PS so often (say, 5 or 10 seconds) and optionally tweaking the formula where you set the corner radius as well, if you want to keep it simple. Otherwise, some constant monitoring system for the monitor variables would be needed (e.g. a Calc measure getting #SCREENAREAWIDTH# and executing some bangs in its OnChangeAction), for better fine tuning.

That's about it. It's not great, but not bad either - things can be detected and done, but not in an entirely automatic way.
You do not have the required permissions to view the files attached to this post.
SubjunctiveQuaver
Posts: 6
Joined: April 18th, 2022, 1:53 pm

Re: Rounded Screen Corners

Post by SubjunctiveQuaver »

[UPDATE -- see next post for a rmskin file] [EDIT: changed AutoSelectScreen to 0 to fix repositioning bug on restart]

O.O thanks for all that, I will take a look into this another time lol, but yeah for clarity's sake it might be easier to just have it modified by the user (unless I can make sure the other implementation works, but I'm a bit busy right now).

Also it's funny, I tried running the PowerShell script and "125%" is actually 200%/100% for me (the recommended settings); on my main monitor, 100% is actually 175% in settings, and 150% is 225%... so I wonder if all of that is not even necessarily consistent across computers...!!

Here is the code:

[SkinsFolder]\Rounded Corners Top\Rounded Corners Top.ini

Code: Select all

[Variables]
DisplayScale=100
CornerRadius=(8*#DisplayScale#/100)
CornerColor=0,0,0

[Rainmeter]
Update=1000
DynamicWindowSize=1
OnRefreshAction=[!AutoSelectScreen 0][!ClickThrough 1][!Draggable 0][!KeepOnScreen 1][!SnapEdges 1][!ZPos 2]

[MeterShapeCorners]
Meter=Shape
Shape=Rectangle 0,0,(#ScreenAreaWidth#),(#CornerRadius#) | Fill Color #CornerColor# | StrokeWidth 0
Shape2=Rectangle 0,0,(#ScreenAreaWidth#),(#CornerRadius#*2),#CornerRadius# | Fill Color 0,0,0,0
Shape3=Combine Shape | Exclude Shape2
OnUpdateAction=[!Move (#ScreenAreaX#) (#ScreenAreaY#)]
DynamicVariables=1

[Metadata]
Name=Rounded Corners Top
Author=eclectic-tech, RyanClark, stupd, istir, Yincognito, SubjunctiveQuaver
Information=Code by eclectic-tech, RyanClark, istir, Yincognito and SubjunctiveQuaver at https://forum.rainmeter.net/viewtopic.php?t=25780. Ensure you also have the "Rounded Corners Bottom" skin enabled. Use the "display monitor" setting for multiple monitors. Corner radius set to match Windows 11's window corners (set display scale to match your display).
Version=1.1.1
License=Creative Commons Attribution - Non - Commercial - Share Alike 3.0
[SkinsFolder]\Rounded Corners Bottom\Rounded Corners Bottom.ini

Code: Select all

[Variables]
DisplayScale=100
CornerRadius=(8*#DisplayScale#/100)
CornerColor=0,0,0

[Rainmeter]
Update=1000
DynamicWindowSize=1
OnRefreshAction=[!AutoSelectScreen 0][!ClickThrough 1][!Draggable 0][!KeepOnScreen 1][!SnapEdges 1][!ZPos 2]

[MeterShapeCorners]
Meter=Shape
Shape=Rectangle 0,0,(#ScreenAreaWidth#),(#CornerRadius#) | Fill Color #CornerColor# | StrokeWidth 0
Shape2=Rectangle 0,(-#CornerRadius#),(#ScreenAreaWidth#),(#CornerRadius#*2),#CornerRadius# | Fill Color 0,0,0,0
Shape3=Combine Shape | Exclude Shape2
OnUpdateAction=[!Move (#ScreenAreaX#) (#ScreenAreaY#+#ScreenAreaHeight#-#CornerRadius#)]
DynamicVariables=1

[Metadata]
Name=Rounded Corners Bottom
Author=eclectic-tech, RyanClark, stupd, istir, Yincognito, SubjunctiveQuaver
Information=Code by eclectic-tech, RyanClark, istir, Yincognito and SubjunctiveQuaver at https://forum.rainmeter.net/viewtopic.php?t=25780. Ensure you also have the "Rounded Corners Top" skin enabled. Use the "display monitor" setting for multiple monitors. Corner radius set to match Windows 11's window corners (set display scale to match your display).
Version=1.1.1
License=Creative Commons Attribution - Non - Commercial - Share Alike 3.0
Last edited by SubjunctiveQuaver on April 20th, 2022, 2:17 am, edited 2 times in total.
SubjunctiveQuaver
Posts: 6
Joined: April 18th, 2022, 1:53 pm

Re: Rounded Screen Corners

Post by SubjunctiveQuaver »

[UPDATE: v1.1.1 with fix for forgetting monitor upon restart]

Update: made a skin package with both skins in it at once. Just need to load both skins (and duplicate the outer folder for each monitor), change scale settings if necessary (set to 100% by default) using the "edit" option, and choose the monitor:
Rounded Corners_1.1.1.rmskin
You do not have the required permissions to view the files attached to this post.
Last edited by SubjunctiveQuaver on April 20th, 2022, 2:17 am, edited 2 times in total.
User avatar
Yincognito
Rainmeter Sage
Posts: 4806
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: Rounded Screen Corners

Post by Yincognito »

SubjunctiveQuaver wrote: April 19th, 2022, 3:00 pm O.O thanks for all that, I will take a look into this another time lol, but yeah for clarity's sake it might be easier to just have it modified by the user (unless I can make sure the other implementation works, but I'm a bit busy right now).

Also it's funny, I tried running the PowerShell script and "125%" is actually 200%/100% for me (the recommended settings); on my main monitor, 100% is actually 175% in settings, and 150% is 225%... so I wonder if all of that is not even necessarily consistent across computers...!!
Indeed, it's easier for the user to manually set his screen scaling like you wrote in your code, but since you asked for a relatively "automatic" way of getting that, well, there was your answer, LOL. Unfortunately, it's not fully automatic, but it's as close as it can get, with the information we currently are aware of. Yeah, I already mentioned that the above method is complicated by the fact that systems / monitors will have different "recommended" and additional percentual values - if it was known what -1, 0, 1, 2 and so on from the registry translate to in the Settings combobox, there would be no need for a $dpicode array variable that can be manually edited by the user, but that thing is up to Microsoft. Here is a link that explains some of these things, but as usual with Microsoft, it doesn't get into how a regular user can easily interpret such values using in the OS settings, unless one goes the C++ route.
SubjunctiveQuaver
Posts: 6
Joined: April 18th, 2022, 1:53 pm

Re: Rounded Screen Corners

Post by SubjunctiveQuaver »

Hi, I've noticed a bug with the implementation (or something else); upon quitting and restarting Rainmeter, the rounded corner on the bottom of monitor 2 always reverts back to monitor 1 in the "manage" page, and I have to move it every time. Not sure what's causing it from first glance (looking at the code)... the top corners are fine and remain on the 2nd monitor. I've tried changing KeepOnScreen to 0 but that doesn't seem to be the issue...

UPDATE: it was AutoSelectScreen, it would set the screen back to the main monitor for some reason. I've changed it to 0, and it seems to work now. Also updated all the code above with the newest version :)