Refactor Polling Mechanism: Implement Class-Based Poller with Start/Stop Control (#528)

* custom module updates to class based.

* Finish poller logic.

* Use composition for pollers

* Rename poller

* Handle recorder polling.

* Fix quotes in bash command

* Remove logs
This commit is contained in:
Jas Singh
2024-11-23 03:55:00 -08:00
committed by GitHub
parent c10c9d0e93
commit a4f5fb5917
26 changed files with 460 additions and 169 deletions

View File

@@ -1,77 +0,0 @@
import GLib from 'gi://GLib?version=2.0';
import { GenericFunction } from 'lib/types/customModules/generic';
import { Bind } from 'lib/types/variable';
import { Variable as VariableType } from 'types/variable';
/**
* @param {VariableType<T>} targetVariable - The Variable to update with the function's result.
* @param {Array<Bind>} trackers - Array of trackers to watch.
* @param {Bind} pollingInterval - The polling interval in milliseconds.
* @param {GenericFunction<T, P>} someFunc - The function to execute at each interval, which updates the Variable.
* @param {...P} params - Parameters to pass to someFunc.
*/
export const pollVariable = <T, P extends unknown[], F extends GenericFunction<T, P>>(
targetVariable: VariableType<T>,
trackers: Array<Bind>,
pollingInterval: Bind,
someFunc: F,
...params: P
): void => {
let intervalInstance: number | null = null;
const intervalFn = (pollIntrvl: number): void => {
if (intervalInstance !== null) {
GLib.source_remove(intervalInstance);
}
intervalInstance = Utils.interval(pollIntrvl, () => {
targetVariable.value = someFunc(...params);
});
};
Utils.merge([pollingInterval, ...trackers], (pollIntrvl: number) => {
intervalFn(pollIntrvl);
});
};
/**
* @param {VariableType<T>} targetVariable - The Variable to update with the result of the command.
* @param {Array<Bind>} trackers - Array of trackers to watch.
* @param {Bind} pollingInterval - The polling interval in milliseconds.
* @param {string} someCommand - The bash command to execute.
* @param {GenericFunction<T, [unknown, ...P]>} someFunc - The function to execute after processing the command result;
* with the first argument being the result of the command execution.
* @param {...P} params - Additional parameters to pass to someFunc.
*/
export const pollVariableBash = <T, P extends unknown[], F extends GenericFunction<T, [string, ...P]>>(
targetVariable: VariableType<T>,
trackers: Array<Bind>,
pollingInterval: Bind,
someCommand: string,
someFunc: F,
...params: P
): void => {
let intervalInstance: number | null = null;
const intervalFn = (pollIntrvl: number): void => {
if (intervalInstance !== null) {
GLib.source_remove(intervalInstance);
}
intervalInstance = Utils.interval(pollIntrvl, () => {
Utils.execAsync(`bash -c "${someCommand}"`)
.then((res: string) => {
try {
targetVariable.value = someFunc(res, ...params);
} catch (error) {
console.warn(`An error occurred when running interval bash function: ${error}`);
}
})
.catch((err) => console.error(`Error running command "${someCommand}": ${err}`));
});
};
Utils.merge([pollingInterval, ...trackers], (pollIntrvl: number) => {
intervalFn(pollIntrvl);
});
};

View File

@@ -1,16 +1,14 @@
import options from 'options';
// Module initializer
import { module } from '../module';
import options from 'options';
import Button from 'types/widgets/button';
// Utility Methods
import { inputHandler } from 'customModules/utils';
import { computeCPU } from './computeCPU';
import { pollVariable } from 'customModules/PollVar';
import { BarBoxChild } from 'lib/types/bar';
import { Attribute, Child } from 'lib/types/widget';
import { FunctionPoller } from 'lib/poller/FunctionPoller';
// All the user configurable options for the cpu module that are needed
const { label, round, leftClick, rightClick, middleClick, scrollUp, scrollDown, pollingInterval, icon } =
@@ -18,7 +16,8 @@ const { label, round, leftClick, rightClick, middleClick, scrollUp, scrollDown,
export const cpuUsage = Variable(0);
pollVariable(
// Instantiate the Poller class for CPU usage polling
const cpuPoller = new FunctionPoller<number, []>(
// Variable to poll and update with the result of the function passed in
cpuUsage,
// Variables that should trigger the polling function to update when they change
@@ -29,6 +28,8 @@ pollVariable(
computeCPU,
);
cpuPoller.initialize('cpu');
export const Cpu = (): BarBoxChild => {
const renderLabel = (cpuUsg: number, rnd: boolean): string => {
return rnd ? `${Math.round(cpuUsg)}%` : `${cpuUsg.toFixed(2)}%`;

View File

@@ -2,14 +2,14 @@ import GLib from 'gi://GLib?version=2.0';
import { convertCelsiusToFahrenheit } from 'globals/weather';
import { UnitType } from 'lib/types/weather';
import options from 'options';
import { Variable } from 'types/variable';
import { Variable as VariableType } from 'types/variable';
const { sensor } = options.bar.customModules.cpuTemp;
/**
* Retrieves the current CPU temperature.
* @returns CPU temperature in degrees Celsius
*/
export const getCPUTemperature = (round: Variable<boolean>, unit: Variable<UnitType>): number => {
export const getCPUTemperature = (round: VariableType<boolean>, unit: VariableType<UnitType>): number => {
try {
if (sensor.value.length === 0) {
return 0;
@@ -23,13 +23,13 @@ export const getCPUTemperature = (round: Variable<boolean>, unit: Variable<UnitT
return 0;
}
let decimalTemp = parseInt(tempInfo) / 1000;
let decimalTemp = parseInt(tempInfo, 10) / 1000;
if (unit.value === 'imperial') {
decimalTemp = convertCelsiusToFahrenheit(decimalTemp);
}
return round ? Math.round(decimalTemp) : parseFloat(decimalTemp.toFixed(2));
return round.value ? Math.round(decimalTemp) : parseFloat(decimalTemp.toFixed(2));
} catch (error) {
console.error('Error calculating CPU Temp:', error);
return 0;

View File

@@ -8,9 +8,11 @@ import Button from 'types/widgets/button';
// Utility Methods
import { inputHandler } from 'customModules/utils';
import { getCPUTemperature } from './helpers';
import { pollVariable } from 'customModules/PollVar';
import { BarBoxChild } from 'lib/types/bar';
import { Attribute, Child } from 'lib/types/widget';
import { FunctionPoller } from 'lib/poller/FunctionPoller';
import { Variable as VariableType } from 'types/variable';
import { UnitType } from 'lib/types/weather';
// All the user configurable options for the cpu module that are needed
const {
@@ -30,7 +32,7 @@ const {
export const cpuTemp = Variable(0);
pollVariable(
const cpuTempPoller = new FunctionPoller<number, [VariableType<boolean>, VariableType<UnitType>]>(
// Variable to poll and update with the result of the function passed in
cpuTemp,
// Variables that should trigger the polling function to update when they change
@@ -43,6 +45,8 @@ pollVariable(
unit,
);
cpuTempPoller.initialize('cputemp');
export const CpuTemp = (): BarBoxChild => {
const cpuTempModule = module({
textIcon: icon.bind('value'),

View File

@@ -1,6 +1,6 @@
import { Variable as TVariable } from 'types/variable';
export const isActiveCommand = `bash -c "pgrep -x "hypridle" > /dev/null && echo "yes" || echo "no""`;
export const isActiveCommand = `bash -c "pgrep -x 'hypridle' &>/dev/null && echo 'yes' || echo 'no'"`;
export const isActive = Variable(false);

View File

@@ -5,8 +5,8 @@ import { inputHandler, throttleInput } from 'customModules/utils';
import Button from 'types/widgets/button';
import { Attribute, Child } from 'lib/types/widget';
import { BarBoxChild } from 'lib/types/bar';
import { pollVariable } from 'customModules/PollVar';
import { checkIdleStatus, isActive, toggleIdle } from './helpers';
import { FunctionPoller } from 'lib/poller/FunctionPoller';
const { label, pollingInterval, onIcon, offIcon, onLabel, offLabel, rightClick, middleClick, scrollUp, scrollDown } =
options.bar.customModules.hypridle;
@@ -15,7 +15,14 @@ const dummyVar = Variable(undefined);
checkIdleStatus();
pollVariable(dummyVar, [], pollingInterval.bind('value'), checkIdleStatus);
const idleStatusPoller = new FunctionPoller<undefined, []>(
dummyVar,
[],
pollingInterval.bind('value'),
checkIdleStatus,
);
idleStatusPoller.initialize('hypridle');
const throttledToggleIdle = throttleInput(() => toggleIdle(isActive), 1000);

View File

@@ -4,7 +4,7 @@ import { Variable as TVariable } from 'types/variable';
const { temperature } = options.bar.customModules.hyprsunset;
export const isActiveCommand = `bash -c "pgrep -x "hyprsunset" > /dev/null && echo "yes" || echo "no""`;
export const isActiveCommand = `bash -c "pgrep -x 'hyprsunset' > /dev/null && echo 'yes' || echo 'no'"`;
export const isActive = Variable(false);

View File

@@ -5,8 +5,8 @@ import { inputHandler, throttleInput } from 'customModules/utils';
import Button from 'types/widgets/button';
import { Attribute, Child } from 'lib/types/widget';
import { BarBoxChild } from 'lib/types/bar';
import { pollVariable } from 'customModules/PollVar';
import { checkSunsetStatus, isActive, toggleSunset } from './helpers';
import { FunctionPoller } from 'lib/poller/FunctionPoller';
const {
label,
@@ -26,7 +26,9 @@ const dummyVar = Variable(undefined);
checkSunsetStatus();
pollVariable(dummyVar, [], pollingInterval.bind('value'), checkSunsetStatus);
const sunsetPoller = new FunctionPoller<undefined, []>(dummyVar, [], pollingInterval.bind('value'), checkSunsetStatus);
sunsetPoller.initialize('hyprsunset');
const throttledToggleSunset = throttleInput(() => toggleSunset(isActive), 1000);

View File

@@ -3,13 +3,14 @@ import options from 'options';
import { module } from '../module';
import { inputHandler } from 'customModules/utils';
import { computeNetwork } from './computeNetwork';
import { BarBoxChild, NetstatLabelType } from 'lib/types/bar';
import { BarBoxChild, NetstatLabelType, RateUnit } from 'lib/types/bar';
import Button from 'types/widgets/button';
import { NetworkResourceData } from 'lib/types/customModules/network';
import { NETWORK_LABEL_TYPES } from 'lib/types/defaults/bar';
import { GET_DEFAULT_NETSTAT_DATA } from 'lib/types/defaults/netstat';
import { pollVariable } from 'customModules/PollVar';
import { Attribute, Child } from 'lib/types/widget';
import { FunctionPoller } from 'lib/poller/FunctionPoller';
import { Variable as TVariable } from 'types/variable';
const {
label,
@@ -27,7 +28,10 @@ const {
export const networkUsage = Variable<NetworkResourceData>(GET_DEFAULT_NETSTAT_DATA(rateUnit.value));
pollVariable(
const netstatPoller = new FunctionPoller<
NetworkResourceData,
[round: TVariable<boolean>, interfaceNameVar: TVariable<string>, dataType: TVariable<RateUnit>]
>(
// Variable to poll and update with the result of the function passed in
networkUsage,
// Variables that should trigger the polling function to update when they change
@@ -48,6 +52,8 @@ pollVariable(
rateUnit,
);
netstatPoller.initialize('netstat');
export const Netstat = (): BarBoxChild => {
const renderNetworkLabel = (lblType: NetstatLabelType, network: NetworkResourceData): string => {
switch (lblType) {

View File

@@ -16,8 +16,9 @@ import { BarBoxChild, ResourceLabelType } from 'lib/types/bar';
// Global Constants
import { LABEL_TYPES } from 'lib/types/defaults/bar';
import { pollVariable } from 'customModules/PollVar';
import { Attribute, Child } from 'lib/types/widget';
import { FunctionPoller } from 'lib/poller/FunctionPoller';
import { Variable as TVariable } from 'types/variable';
// All the user configurable options for the ram module that are needed
const { label, labelType, round, leftClick, rightClick, middleClick, pollingInterval, icon } =
@@ -26,7 +27,15 @@ const { label, labelType, round, leftClick, rightClick, middleClick, pollingInte
const defaultRamData: GenericResourceData = { total: 0, used: 0, percentage: 0, free: 0 };
const ramUsage = Variable<GenericResourceData>(defaultRamData);
pollVariable(ramUsage, [round.bind('value')], pollingInterval.bind('value'), calculateRamUsage, round);
const ramPoller = new FunctionPoller<GenericResourceData, [TVariable<boolean>]>(
ramUsage,
[round.bind('value')],
pollingInterval.bind('value'),
calculateRamUsage,
round,
);
ramPoller.initialize('ram');
export const Ram = (): BarBoxChild => {
const ramModule = module({

View File

@@ -1,14 +1,14 @@
import options from 'options';
import { module } from '../module';
import { formatTooltip, inputHandler, renderResourceLabel } from 'customModules/utils';
import { computeStorage } from './computeStorage';
import { BarBoxChild, ResourceLabelType } from 'lib/types/bar';
import { GenericResourceData } from 'lib/types/customModules/generic';
import Button from 'types/widgets/button';
import { LABEL_TYPES } from 'lib/types/defaults/bar';
import { pollVariable } from 'customModules/PollVar';
import { Attribute, Child } from 'lib/types/widget';
import { FunctionPoller } from 'lib/poller/FunctionPoller';
import { Variable as TVariable } from 'types/variable';
const { label, labelType, icon, round, leftClick, rightClick, middleClick, pollingInterval } =
options.bar.customModules.storage;
@@ -17,7 +17,15 @@ const defaultStorageData = { total: 0, used: 0, percentage: 0, free: 0 };
const storageUsage = Variable<GenericResourceData>(defaultStorageData);
pollVariable(storageUsage, [round.bind('value')], pollingInterval.bind('value'), computeStorage, round);
const storagePoller = new FunctionPoller<GenericResourceData, [TVariable<boolean>]>(
storageUsage,
[round.bind('value')],
pollingInterval.bind('value'),
computeStorage,
round,
);
storagePoller.initialize('storage');
export const Storage = (): BarBoxChild => {
const storageModule = module({

View File

@@ -3,10 +3,10 @@ import { module } from '../module';
import { inputHandler } from 'customModules/utils';
import Button from 'types/widgets/button';
import { Variable as VariableType } from 'types/variable';
import { pollVariableBash } from 'customModules/PollVar';
import { Variable as TVariable } from 'types/variable';
import { Attribute, Child } from 'lib/types/widget';
import { BarBoxChild } from 'lib/types/bar';
import { BashPoller } from 'lib/poller/BashPoller';
const {
updateCommand,
@@ -21,7 +21,7 @@ const {
scrollDown,
} = options.bar.customModules.updates;
const pendingUpdates: VariableType<string> = Variable('0');
const pendingUpdates: TVariable<string> = Variable('0');
const postInputUpdater = Variable(true);
const processUpdateCount = (updateCount: string): string => {
@@ -29,7 +29,7 @@ const processUpdateCount = (updateCount: string): string => {
return `${updateCount.padStart(2, '0')}`;
};
pollVariableBash(
const updatesPoller = new BashPoller<string, []>(
pendingUpdates,
[padZero.bind('value'), postInputUpdater.bind('value')],
pollingInterval.bind('value'),
@@ -37,6 +37,8 @@ pollVariableBash(
processUpdateCount,
);
updatesPoller.initialize('updates');
export const Updates = (): BarBoxChild => {
const updatesModule = module({
textIcon: icon.bind('value'),

1
globals.d.ts vendored
View File

@@ -1,4 +1,3 @@
// globals.d.ts
/* eslint-disable no-var */
import { Options, Variable as VariableType } from 'types/variable';

View File

@@ -10,8 +10,6 @@ globalThis.isWindowVisible = (windowName: string): boolean => {
};
globalThis.setLayout = (layout: string): string => {
console.log(layout);
try {
const layoutJson = JSON.parse(layout);
const { layouts } = options.bar;

90
lib/poller/BashPoller.ts Normal file
View File

@@ -0,0 +1,90 @@
import { Variable as VariableType } from 'types/variable';
import { Bind } from 'lib/types/variable';
import { GenericFunction } from 'lib/types/customModules/generic';
import { BarModule } from 'lib/types/options';
import { Poller } from './Poller';
/**
* A class that manages polling of a variable by executing a bash command at specified intervals.
*/
export class BashPoller<Value, Parameters extends unknown[]> {
private poller: Poller;
private params: Parameters;
/**
* Creates an instance of BashPoller.
*
* @param targetVariable - The target variable to poll.
* @param trackers - An array of trackers to monitor.
* @param pollingInterval - The interval at which polling occurs.
* @param updateCommand - The command to update the target variable.
* @param pollingFunction - The function to execute during each poll.
* @param params - Additional parameters for the polling function.
*
* @example
*
* ```ts
* //##################### EXAMPLE ##########################
* const updatesPoller = new BashPoller<string, []>(
* pendingUpdates,
* [padZero.bind('value'), postInputUpdater.bind('value')],
* pollingInterval.bind('value'),
* updateCommand.value,
* processUpdateCount,
* );
* //#######################################################
*
* ```
*/
constructor(
private targetVariable: VariableType<Value>,
private trackers: Bind[],
private pollingInterval: Bind,
private updateCommand: string,
private pollingFunction: GenericFunction<Value, [string, ...Parameters]>,
...params: Parameters
) {
this.params = params;
this.poller = new Poller(this.pollingInterval, this.trackers, this.execute);
}
/**
* Executes the bash command specified in the updateCommand property.
*
* The result of the command is processed by the pollingFunction and
* assigned to the targetVariable.
*/
public execute = async (): Promise<void> => {
try {
const res = await Utils.execAsync(`bash -c "${this.updateCommand}"`);
this.targetVariable.value = await this.pollingFunction(res, ...this.params);
} catch (error) {
console.error(`Error executing bash command "${this.updateCommand}":`, error);
}
};
/**
* Starts the polling process.
*/
public start(): void {
this.poller.start();
}
/**
* Stops the polling process.
*/
public stop(): void {
this.poller.stop();
}
/**
* Initializes the poller with the specified module.
*
* @param moduleName - The name of the module to initialize.
*/
public initialize(moduleName?: BarModule): void {
this.poller.initialize(moduleName);
}
}

View File

@@ -0,0 +1,86 @@
import { Variable as VariableType } from 'types/variable';
import { Bind } from 'lib/types/variable';
import { GenericFunction } from 'lib/types/customModules/generic';
import { BarModule } from 'lib/types/options';
import { Poller } from './Poller';
/**
* A class that manages polling of a variable by executing a generic function at specified intervals.
*/
export class FunctionPoller<Value, Parameters extends unknown[] = []> {
private poller: Poller;
private params: Parameters;
/**
* Creates an instance of FunctionPoller.
*
* @param targetVariable - The target variable to poll.
* @param trackers - An array of trackers to monitor.
* @param pollingInterval - The interval at which polling occurs.
* @param pollingFunction - The function to execute during each poll.
* @param params - Additional parameters for the polling function.
*
* @example
*
* ```ts
* //##################### EXAMPLE ##########################
* const cpuPoller = new FunctionPoller<number, []>(
* cpuUsage,
* [round.bind('value')],
* pollingInterval.bind('value'),
* computeCPU,
* );
* //#######################################################
*
* ```
*/
constructor(
private targetVariable: VariableType<Value>,
private trackers: Bind[],
private pollingInterval: Bind,
private pollingFunction: GenericFunction<Value, Parameters>,
...params: Parameters
) {
this.params = params;
this.poller = new Poller(this.pollingInterval, this.trackers, this.execute);
}
/**
* Executes the polling function with the provided parameters.
*
* The result of the function is assigned to the target variable.
*/
private execute = async (): Promise<void> => {
try {
const result = await this.pollingFunction(...this.params);
this.targetVariable.value = result;
} catch (error) {
console.error('Error executing polling function:', error);
}
};
/**
* Starts the polling process.
*/
public start(): void {
this.poller.start();
}
/**
* Stops the polling process.
*/
public stop(): void {
this.poller.stop();
}
/**
* Initializes the poller with the specified module.
*
* @param moduleName - The name of the module to initialize.
*/
public initialize(moduleName?: BarModule): void {
this.poller.initialize(moduleName);
}
}

107
lib/poller/Poller.ts Normal file
View File

@@ -0,0 +1,107 @@
import GLib from 'gi://GLib?version=2.0';
import { Bind } from 'lib/types/variable';
import { BarModule } from 'lib/types/options';
import { getLayoutItems } from 'lib/utils';
const { layouts } = options.bar;
/**
* A class that manages the polling lifecycle, including interval management and execution state.
*/
export class Poller {
private intervalInstance: number | null = null;
private isExecuting: boolean = false;
private pollingFunction: () => Promise<void>;
/**
* Creates an instance of Poller.
* @param pollingInterval - The interval at which polling occurs.
* @param trackers - An array of trackers to monitor.
* @param pollingFunction - The function to execute during each poll.
*/
constructor(
private pollingInterval: Bind,
private trackers: Bind[],
pollingFunction: () => Promise<void>,
) {
this.pollingFunction = pollingFunction;
}
/**
* Starts the polling process by setting up the interval.
*/
public start(): void {
Utils.merge([this.pollingInterval, ...this.trackers], (intervalMs: number) => {
this.executePolling(intervalMs);
});
}
/**
* Stops the polling process and cleans up resources.
*/
public stop(): void {
if (this.intervalInstance !== null) {
GLib.source_remove(this.intervalInstance);
this.intervalInstance = null;
}
}
/**
* Initializes the polling based on module usage.
*
* If not module is provided then we can safely assume that we want
* to always run the pollig interval.
*
* @param moduleName - The name of the module to initialize.
*/
public initialize(moduleName?: BarModule): void {
if (moduleName === undefined) {
return this.start();
}
const initialModules = getLayoutItems();
if (initialModules.includes(moduleName)) {
this.start();
} else {
this.stop();
}
layouts.connect('changed', () => {
const usedModules = getLayoutItems();
if (usedModules.includes(moduleName)) {
this.start();
} else {
this.stop();
}
});
}
/**
* Executes the polling function at the specified interval.
*
* @param intervalMs - The polling interval in milliseconds.
*/
private executePolling(intervalMs: number): void {
if (this.intervalInstance !== null) {
GLib.source_remove(this.intervalInstance);
}
this.intervalInstance = Utils.interval(intervalMs, async () => {
if (this.isExecuting) {
return;
}
this.isExecuting = true;
try {
await this.pollingFunction();
} catch (error) {
console.error('Error during polling execution:', error);
} finally {
this.isExecuting = false;
}
});
}
}

View File

@@ -1,4 +1,4 @@
export type GenericFunction<T, P extends unknown[] = unknown[]> = (...args: P) => T;
export type GenericFunction<Value, Parameters extends unknown[]> = (...args: Parameters) => Promise<Value> | Value;
export type GenericResourceMetrics = {
total: number;

View File

@@ -15,8 +15,38 @@ export type RecursiveOptionsObject = {
};
export type BarLocation = 'top' | 'bottom';
export type BarModule =
| 'battery'
| 'dashboard'
| 'workspaces'
| 'windowtitle'
| 'media'
| 'notifications'
| 'volume'
| 'network'
| 'bluetooth'
| 'clock'
| 'ram'
| 'cpu'
| 'cputemp'
| 'storage'
| 'netstat'
| 'kbinput'
| 'updates'
| 'submap'
| 'weather'
| 'power'
| 'systray'
| 'hypridle'
| 'hyprsunset';
export type BarLayout = {
[key: string]: Layout;
left: BarModule[];
middle: BarModule[];
right: BarModule[];
};
export type BarLayouts = {
[key: string]: BarLayout;
};
export type Unit = 'imperial' | 'metric';

View File

@@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { type Application } from 'types/service/applications';
import { NotificationAnchor } from './types/options';
import { BarModule, NotificationAnchor } from './types/options';
import { OSDAnchor } from 'lib/types/options';
import icons, { substitutes } from './icons';
import Gtk from 'gi://Gtk?version=3.0';
@@ -18,6 +18,29 @@ import options from 'options';
export type Binding<T> = import('types/service').Binding<any, any, T>;
/**
* Retrieves all unique layout items from the bar options.
*
* @returns An array of unique layout items.
*/
export const getLayoutItems = (): BarModule[] => {
const { layouts } = options.bar;
const itemsInLayout: BarModule[] = [];
Object.keys(layouts.value).forEach((monitor) => {
const leftItems = layouts.value[monitor].left;
const rightItems = layouts.value[monitor].right;
const middleItems = layouts.value[monitor].middle;
itemsInLayout.push(...leftItems);
itemsInLayout.push(...middleItems);
itemsInLayout.push(...rightItems);
});
return [...new Set(itemsInLayout)];
};
/**
* @returns substitute icon || name || fallback icon
*/

View File

@@ -35,7 +35,7 @@ import Button from 'types/widgets/button.js';
import Gtk from 'types/@girs/gtk-3.0/gtk-3.0.js';
import './SideEffects';
import { BarLayout, WindowLayer } from 'lib/types/options.js';
import { BarLayout, BarLayouts, WindowLayer } from 'lib/types/options.js';
import { Attribute, Child } from 'lib/types/widget.js';
import Window from 'types/widgets/window.js';
@@ -43,40 +43,7 @@ const { layouts } = options.bar;
const { location } = options.theme.bar;
const { location: borderLocation } = options.theme.bar.border;
export type BarWidget = keyof typeof widget;
type Section =
| 'battery'
| 'dashboard'
| 'workspaces'
| 'windowtitle'
| 'media'
| 'notifications'
| 'volume'
| 'network'
| 'bluetooth'
| 'clock'
| 'ram'
| 'cpu'
| 'cputemp'
| 'storage'
| 'netstat'
| 'kbinput'
| 'updates'
| 'submap'
| 'weather'
| 'power'
| 'systray'
| 'hypridle'
| 'hyprsunset';
type Layout = {
left: Section[];
middle: Section[];
right: Section[];
};
const getLayoutForMonitor = (monitor: number, layouts: BarLayout): Layout => {
const getLayoutForMonitor = (monitor: number, layouts: BarLayouts): BarLayout => {
const matchingKey = Object.keys(layouts).find((key) => key === monitor.toString());
const wildcard = Object.keys(layouts).find((key) => key === '*');
@@ -95,7 +62,7 @@ const getLayoutForMonitor = (monitor: number, layouts: BarLayout): Layout => {
};
};
const isLayoutEmpty = (layout: Layout): boolean => {
const isLayoutEmpty = (layout: BarLayout): boolean => {
const isLeftSectionEmpty = !Array.isArray(layout.left) || layout.left.length === 0;
const isRightSectionEmpty = !Array.isArray(layout.right) || layout.right.length === 0;
const isMiddleSectionEmpty = !Array.isArray(layout.middle) || layout.middle.length === 0;

View File

@@ -1,4 +1,5 @@
const hyprland = await Service.import('hyprland');
import { BashPoller } from 'lib/poller/BashPoller';
import { Attribute, BoxWidget, Child } from 'lib/types/widget';
import options from 'options';
import { Variable as VarType } from 'types/variable';
@@ -9,18 +10,26 @@ import Label from 'types/widgets/label';
const { left, right } = options.menus.dashboard.shortcuts;
const Shortcuts = (): BoxWidget => {
const isRecording = Variable(false, {
poll: [
1000,
`${App.configDir}/services/screen_record.sh status`,
(out): boolean => {
if (out === 'recording') {
const pollingInterval = Variable(1000);
const isRecording = Variable(false);
const handleRecorder = (commandOutput: string): boolean => {
if (commandOutput === 'recording') {
return true;
}
return false;
},
],
});
};
const recordingPoller = new BashPoller<boolean, []>(
isRecording,
[],
pollingInterval.bind('value'),
`${App.configDir}/services/screen_record.sh status`,
handleRecorder,
);
recordingPoller.initialize();
const handleClick = (action: string, tOut: number = 250): void => {
App.closeWindow('dashboardmenu');

View File

@@ -4,7 +4,7 @@ import { KbLabelType } from 'lib/types/customModules/kbLayout';
import {
ActiveWsIndicator,
BarButtonStyles,
BarLayout,
BarLayouts,
BarLocation,
BluetoothBatteryState,
BorderLocation,
@@ -872,7 +872,7 @@ const options = mkOptions(OPTIONS, {
bar: {
scrollSpeed: opt(5),
layouts: opt<BarLayout>({
layouts: opt<BarLayouts>({
'1': {
left: ['dashboard', 'workspaces', 'windowtitle'],
middle: ['media'],

View File

@@ -2,8 +2,7 @@
// @ts-expect-error: This import is a special directive that tells the compiler to use the GTop library
import GTop from 'gi://GTop';
import { pollVariable } from 'customModules/PollVar';
import { FunctionPoller } from 'lib/poller/FunctionPoller';
class Cpu {
private updateFrequency = Variable(2000);
@@ -15,7 +14,14 @@ class Cpu {
GTop.glibtop_get_cpu(this.previousCpuData);
this.calculateUsage = this.calculateUsage.bind(this);
pollVariable(this.cpu, [], this.updateFrequency.bind('value'), this.calculateUsage);
const cpuPoller = new FunctionPoller<number, []>(
this.cpu,
[],
this.updateFrequency.bind('value'),
this.calculateUsage,
);
cpuPoller.start();
}
public calculateUsage(): number {

View File

@@ -2,7 +2,7 @@
const GLib = imports.gi.GLib;
import { pollVariable } from 'customModules/PollVar';
import { FunctionPoller } from 'lib/poller/FunctionPoller';
import { GenericResourceData } from 'lib/types/customModules/generic';
class Ram {
@@ -13,7 +13,14 @@ class Ram {
constructor() {
this.calculateUsage = this.calculateUsage.bind(this);
pollVariable(this.ram, [], this.updateFrequency.bind('value'), this.calculateUsage);
const ramPoller = new FunctionPoller<GenericResourceData, []>(
this.ram,
[],
this.updateFrequency.bind('value'),
this.calculateUsage,
);
ramPoller.start();
}
public calculateUsage(): GenericResourceData {

View File

@@ -3,7 +3,7 @@
// @ts-expect-error: This import is a special directive that tells the compiler to use the GTop library
import GTop from 'gi://GTop';
import { pollVariable } from 'customModules/PollVar';
import { FunctionPoller } from 'lib/poller/FunctionPoller';
import { GenericResourceData } from 'lib/types/customModules/generic';
class Storage {
@@ -14,7 +14,14 @@ class Storage {
constructor() {
this.calculateUsage = this.calculateUsage.bind(this);
pollVariable(this.storage, [], this.updateFrequency.bind('value'), this.calculateUsage);
const storagePoller = new FunctionPoller<GenericResourceData, []>(
this.storage,
[],
this.updateFrequency.bind('value'),
this.calculateUsage,
);
storagePoller.start();
}
public calculateUsage(): GenericResourceData {