Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add cpu, gpu, memory, text file, and weather bar components #297

Merged
merged 39 commits into from
Aug 5, 2023

Conversation

Sewer56
Copy link
Contributor

@Sewer56 Sewer56 commented Apr 8, 2023

Summary

This pull request introduces several new components to GlazeWM, including CPU Usage, GPU Usage, Memory Usage, Text File, and Weather Components. Additionally, a guide for creating custom bar components has been added. Lastly, an IPC subsystem based on ZeroMQ and UTF8 JSON is introduced, allowing for interprocess communication and remote updating of bar components.

Changes

  • Added CPU Usage Bar Component
  • Added GPU Usage Bar Component
  • Added Memory Usage Bar Component
  • Added Text File Bar Component
  • Added Weather Component
  • Added Guide for Custom Bar Components
  • Added IPC Subsystem (Publisher/Subscriber)
  • Added bar component updatable via IPC
  • GlazeWM left/right component sections can now extend past center.
  • GlazeWM will no longer add empty zero space component separators if no separator text is specified.
  • Optimized Runtime Memory Allocation to Near Zero

Demo

rider64_dA3L31LsPt

Contains most of the new controls; in near-stock configuration.

Characteristics

  • Code does not enforce any font etc. for new components.
    • Only icons available in the standard fonts are used e.g. for weather component.
  • All components correctly dispose and survive config reloads.
  • All components behave correctly on multiple displays.
  • Logic is provided via services; in Infrastructure, clean separation from ViewModel.
  • All new components are documented in Readme.
  • Minimal use of external dependencies for new functionality.
  • API/Samples provided for IPC.
  • IPC runs on localhost only; not externally reachable, will not trigger firewall warning.
  • All new code runs efficiently; does not eat CPU cycles for breakfast.

Caveats

CPU Sensors

CPU Core Temperature and Package Power have some caveats (noted in readme):

  • Windows does not report these values natively; to the user.
  • So I used LibreHardwareMonitor to read these sensors directly.
  • Unfortunately, that requires admin.

I cannot confirm these sensors will be correctly read on all processors; as the LHM API returns sensors using inconsistent naming [as strings]. One CPU might use CPU Package for power, while another uses Package. I can confirm it works for Ryzen 5000; cannot confirm for recent Intel platforms. I got the names for recent Intel CPUs based off of online screenshots of LHM.

Another thing to note is using a high update rate might cause very high readouts after resume from sleep/suspend e.g. '20GHz Frequency'; especially if using polling rates greater than 1 per second. This isn't something we can do much about however; there isn't enough sensor data.

Extra Details

Improved Memory Efficiency

Old code in GetProcessOfHandle allocated a lot of memory because:

/// <summary>
/// Get the id of the process that created the window.
/// </summary>
public static Process GetProcessOfHandle(IntPtr handle)
{
  _ = GetWindowThreadProcessId(handle, out var processId);
  return Array.Find(Process.GetProcesses(), process => process.Id == (int)processId);
}

This code would frequently get fired and unnecessarily enumerate all processes in the system; also adding latency to handling window open operations. Not to mention a lot of Gen0 garbage collections.

The line was simply replaced with:

return Process.GetProcessById((int)processId);

Now GC is only fired once in a blue moon.

Components Can Now Extend Past Center

image

Left/Right components can now extend past the center of the bar.
Previously left/right bar components would get clipped at center, even if center and other side were completely empty.

Side Effect: Left/Center/Right can overlap now.

Bar Component: CPU Usage

Displays the current CPU usage.

- type: "cpu usage"
  
  # {0} is substituted by percentage, {1} by current value, {2} by max value 
  # Example: '{1}/{2} MHz ({0}%)'
  #          'CPU {0}%'
  string_format: "CPU {0}%"

  # For formats, see: https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings#standard-format-specifiers.
  percent_format: "00" # Format for {0}.
  current_value_format: "0.00" # Format for {1}.
  max_value_format: "0.00" # Format for {2}.
  refresh_interval_ms: 500 # How often this counter is refreshed
  divide_by: 1000 # Convert MHz to GHz (where appropriate).
  counter: CpuUsage

  # Supported Counters Include:
  # CpuUsage: Overall CPU Usage across All Cores.
  # CpuFrequency: Overall CPU Frequency across All Cores.
  # PackagePower: [Requires Admin] Overall Power used by CPU Package [not guaranteed to work]
  # CoreTemp: [Requires Admin] Average Core Temperature of CPU Package [not guaranteed to work]

Bar Component: GPU Usage

This component has high CPU requirement (compared to others); due to no efficient way to pull data from Windows API. Avoid using low refresh intervals.

- type: "gpu usage"
  string_format: "GPU {0}%" # {0} is substituted by number format
  number_format: "00" # See https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings#standard-format-specifiers.
  refresh_interval_ms: 1000 # How often this counter is refreshed
  flags: Graphics

  # Supported flags
  # Multiple flags can be specified by e.g. `flags: Graphics, VideoDecode, VideoEncode, Copy`

  # Graphics: 3D GPU Engine usage. [Probably what you want]
  # VideoDecode: Load of dedicated video decoding silicon.
  # VideoEncode: Load of dedicated video encoding silicon, i.e. NVENC/AMD AMF/QuickSync.
  # LegacyOverlay: Legacy API for overlaying items over other items.
  # Copy: Load copying data without intervention of CPU e.g. copying framebuffer across screens in multi GPU setup or uploading textures.
  # Security: Workloads related to cryptography, such as encryption, decryption, and secure video processing.
  # Vr: Virtual Reality related workloads.

If multiple GPUs are present; this will average loads between them. I lack a multi-GPU system to implement code to separate them.

Bar Component: Memory Usage

Displays the current Memory usage.

- type: "memory usage"
  # {0} is substituted by percentage, {1} by current value, {2} by max value 
  # Example: '{1}/{2} MB ({0}%)'
  #          '{0}%'
  string_format: "RAM {1}/{2}GB ({0}%)"

  # For formats, see: https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings#standard-format-specifiers.
  percent_format: "00" # Format for {0}.
  current_value_format: "00.00" # Format for {1}.
  max_value_format: "00.00" # Format for {2}.
  refresh_interval_ms: 1000 # How often this counter is refreshed
  divide_by: 1000000000 # Convert to GigaBytes.

  # Supported Counters Include:
  # PhysicalMemory: Current amount of physical RAM in use; i.e. working set.
  # CacheBytes: Amount of cached file data in physical RAM.
  # CommitSize: Retrieves the amount of committed virtual memory (bytes); i.e. which has space reserved on the disk paging file(s).
  # PagedResidentBytes: Size of the active portion of the paged pool in physical memory, storing objects that can be written to disk when they're not in use.
  counter: PhysicalMemory

Bar Component: Text File

For displaying any content without a native integrated widget; updates in real time.

- type: "text file"
  file_path: "PATH_HERE" # path to file

Bar Component: Weather

Uses Open-Meteo API, refreshes every hour.

- type: "weather"
  latitude: 40.6892
  longitude: 74.0445
  format: "{0}{1}°C" # {0} icon, {1} temperature.
  temperature_unit: Celsius # or Fahrenheit
  temperature_format: "0" # Format of {1}
  label_sun: "☀️"
  label_moon: "🌙"
  label_cloud_moon: "🌙☁️"
  label_cloud_sun: ""
  label_cloud_moon_rain: "🌙🌧️"
  label_cloud_sun_rain: "🌦️"
  label_cloud_rain: "🌧️"
  label_snow_flake: "❄️"
  label_thunderstorm: ""
  label_cloud: "☁️"

IPC

GlazeWM includes a component for handling inter-process communication.
It is based ZeroMQ for message passing and UTF8 JSON for serialization, therefore should be portable across many languages.

Refer to Client Source for Possible Commands.

By default Port 49999 is used, you can override this in main bar config.

general:
  net_mq_port: 49999

Bar Component: IPC Label

This component allows you to update its text and style remotely using interprocess communication:

- type: "ipc"
  label_id: "uniqueIdForThisLabel"
  default_text: "placeholder text" # Placeholder

To use this, make a new C# project and add a Project Reference to GlazeWM.IPC.Client; then use it as follows:

// Connect to IPC
using var client = new Client(49999);

// Send an update
client.SendIpcComponentUpdate("uniqueIdForThisLabel", new UpdateIpcComponent()
{
  Text = "This label now has cool text"
});

Usage from Other Programming Languages

If you are interfacing from another programming language, do equivalent of:

_publisher = new PublisherSocket();
_publisher.Connect($"tcp://localhost:{port}");

and simply send update messages.

Check the Messages. folder for list of available messages.

Example payload for IPC Label Component:

{
  "Text":"This is a cool label.",
  "Foreground":"#74FFFF74",
  "Margin":null,
  "Background":null,
  "FontFamily":null,
  "FontWeight":null,
  "FontSize":null,
  "BorderColor":null,
  "BorderRadius":null,
  "BorderWidth":null,
  "Padding":null
}

Misc Note

I made these changes over the course of some spare time I had last weekend (so over ~2 days); hopefully they prove useful.

I was also considering adding window backup/restore via IPC [using a watcher process] for surviving crashes; but people would probably have their own preferences as to detail of that implementation; so I'm leaving it out for now.

GlazeWM.Bar/Components/CpuPercentComponent.xaml.cs Outdated Show resolved Hide resolved
GlazeWM.Bar/Components/WeatherComponentViewModel.cs Outdated Show resolved Hide resolved
GlazeWM.Domain/UserConfigs/BarComponentConfigConverter.cs Outdated Show resolved Hide resolved
GlazeWM.Infrastructure/WindowsApi/MemoryStatsService.cs Outdated Show resolved Hide resolved
GlazeWM.Infrastructure/WindowsApi/MemoryStatsService.cs Outdated Show resolved Hide resolved
GlazeWM.Domain/UserConfigs/BarComponentConfigConverter.cs Outdated Show resolved Hide resolved
GlazeWM.Infrastructure/GlazeWM.Infrastructure.csproj Outdated Show resolved Hide resolved
GlazeWM.Domain/Windows/WindowService.cs Outdated Show resolved Hide resolved
@lars-berger
Copy link
Member

This is probably the craziest PR that's come in so far haha. The amount of features + fixes is huge, and thanks especially for documenting some of the stuff that desperately needed documenting.

Had a quick chat with @notblam regarding the open PRs for weather and system stats bar components (#270 and #253), and we'd be in favour of going with your implementations and just closing those existing ones.

We've had some discussions about IPC before on the Discord. Something that's pretty important IMO is that it should be as newbie friendly as possible. Websockets seemed like the favorable choice since it's easily usable in basically every major language. We had a contributor who even started cooking up an implementation, but it's currently paused and unfinished.

To figure out what to do about the IPC stuff, feel free to join the Discord server. If you'd prefer discussing on Github instead, I'm cool with that too

@lars-berger lars-berger merged commit e24f556 into glzr-io:master Aug 5, 2023
@lars-berger lars-berger changed the title feat: Add New Components and IPC Subsystem to GlazeWM feat: add cpu, gpu, memory, text file, and weather bar components Aug 5, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants