Replaced the underlying structure of Hypridle inhibitor to the Astal Idle Inhibitor module. (#776)
* Update hypridle module to be an all-purpose idle inhibitor module using Astal inhibiting. * Fix types and module code. * Update note * Removed lingering comment. * Remove hypridle from dependencies.
This commit is contained in:
@@ -67,9 +67,6 @@ hyprpicker
|
|||||||
## To enable hyprland's very own blue light filter
|
## To enable hyprland's very own blue light filter
|
||||||
hyprsunset
|
hyprsunset
|
||||||
|
|
||||||
## To enable hyprland's very own idle inhibitor
|
|
||||||
hypridle
|
|
||||||
|
|
||||||
## To click resource/stat bars in the dashboard and open btop
|
## To click resource/stat bars in the dashboard and open btop
|
||||||
btop
|
btop
|
||||||
|
|
||||||
@@ -91,7 +88,7 @@ pacman:
|
|||||||
AUR:
|
AUR:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
yay -S --needed aylurs-gtk-shell-git grimblast-git gpu-screen-recorder-git hyprpicker matugen-bin python-gpustat hyprsunset-git hypridle-git
|
yay -S --needed aylurs-gtk-shell-git grimblast-git gpu-screen-recorder-git hyprpicker matugen-bin python-gpustat hyprsunset-git
|
||||||
```
|
```
|
||||||
|
|
||||||
### Fedora
|
### Fedora
|
||||||
|
|||||||
@@ -71,6 +71,44 @@ export const utilityCommands: Command[] = [
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'isInhibiting',
|
||||||
|
aliases: ['isi'],
|
||||||
|
description: 'Returns the status of the Idle Inhibitor.',
|
||||||
|
category: 'Utility',
|
||||||
|
args: [],
|
||||||
|
handler: (): boolean => {
|
||||||
|
try {
|
||||||
|
return idleInhibit.get();
|
||||||
|
} catch (error) {
|
||||||
|
errorHandler(error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'idleInhibit',
|
||||||
|
aliases: ['idi'],
|
||||||
|
description: 'Enables/Disables the Idle Inhibitor. Toggles the Inhibitor if no parameter is provided.',
|
||||||
|
category: 'Utility',
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
name: 'shouldInhibit',
|
||||||
|
description: 'The boolean value that enables/disables the inhibitor.',
|
||||||
|
type: 'boolean',
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
handler: (args: Record<string, unknown>): boolean => {
|
||||||
|
try {
|
||||||
|
const shouldInhibit = args['shouldInhibit'] ?? !idleInhibit.get();
|
||||||
|
idleInhibit.set(Boolean(shouldInhibit));
|
||||||
|
|
||||||
|
return idleInhibit.get();
|
||||||
|
} catch (error) {
|
||||||
|
errorHandler(error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'migrateConfig',
|
name: 'migrateConfig',
|
||||||
aliases: ['mcfg'],
|
aliases: ['mcfg'],
|
||||||
|
|||||||
@@ -127,6 +127,7 @@ export const Bar = (() => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<window
|
<window
|
||||||
|
inhibit={bind(idleInhibit)}
|
||||||
name={`bar-${hyprlandMonitor}`}
|
name={`bar-${hyprlandMonitor}`}
|
||||||
namespace={`bar-${hyprlandMonitor}`}
|
namespace={`bar-${hyprlandMonitor}`}
|
||||||
className={'bar'}
|
className={'bar'}
|
||||||
|
|||||||
@@ -1,55 +0,0 @@
|
|||||||
import { execAsync, Variable } from 'astal';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the hypridle process is active.
|
|
||||||
*
|
|
||||||
* This command checks if the hypridle process is currently running by using the `pgrep` command.
|
|
||||||
* It returns 'yes' if the process is found and 'no' otherwise.
|
|
||||||
*/
|
|
||||||
export const isActiveCommand = `bash -c "pgrep -x 'hypridle' &>/dev/null && echo 'yes' || echo 'no'"`;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A variable to track the active state of the hypridle process.
|
|
||||||
*/
|
|
||||||
export const isActive = Variable(false);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the active state of the hypridle process.
|
|
||||||
*
|
|
||||||
* This function checks if the hypridle process is currently running and updates the `isActive` variable accordingly.
|
|
||||||
*
|
|
||||||
* @param isActive A Variable<boolean> that tracks the active state of the hypridle process.
|
|
||||||
*/
|
|
||||||
const updateIsActive = (isActive: Variable<boolean>): void => {
|
|
||||||
execAsync(isActiveCommand).then((res) => {
|
|
||||||
isActive.set(res === 'yes');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Toggles the hypridle process on or off based on its current state.
|
|
||||||
*
|
|
||||||
* This function checks if the hypridle process is currently running. If it is not running, it starts the process.
|
|
||||||
* If it is running, it stops the process. The active state is updated accordingly.
|
|
||||||
*
|
|
||||||
* @param isActive A Variable<boolean> that tracks the active state of the hypridle process.
|
|
||||||
*/
|
|
||||||
export const toggleIdle = (isActive: Variable<boolean>): void => {
|
|
||||||
execAsync(isActiveCommand).then((res) => {
|
|
||||||
const toggleIdleCommand =
|
|
||||||
res === 'no' ? `bash -c "nohup hypridle > /dev/null 2>&1 &"` : `bash -c "pkill hypridle"`;
|
|
||||||
|
|
||||||
execAsync(toggleIdleCommand).then(() => updateIsActive(isActive));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks the current status of the hypridle process and updates the active state.
|
|
||||||
*
|
|
||||||
* This function checks if the hypridle process is currently running and updates the `isActive` variable accordingly.
|
|
||||||
*/
|
|
||||||
export const checkIdleStatus = (): undefined => {
|
|
||||||
execAsync(isActiveCommand).then((res) => {
|
|
||||||
isActive.set(res === 'yes');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@@ -1,37 +1,33 @@
|
|||||||
import options from 'src/options';
|
import options from 'src/options';
|
||||||
import { Module } from '../../shared/Module';
|
import { Module } from '../../shared/Module';
|
||||||
import { inputHandler, throttleInput } from '../../utils/helpers';
|
import { inputHandler } from '../../utils/helpers';
|
||||||
import { checkIdleStatus, isActive, toggleIdle } from './helpers';
|
|
||||||
import { FunctionPoller } from '../../../../lib/poller/FunctionPoller';
|
|
||||||
import Variable from 'astal/variable';
|
import Variable from 'astal/variable';
|
||||||
import { bind } from 'astal';
|
import { bind } from 'astal';
|
||||||
import { BarBoxChild } from 'src/lib/types/bar';
|
import { BarBoxChild } from 'src/lib/types/bar';
|
||||||
import { Astal } from 'astal/gtk3';
|
import { Astal } from 'astal/gtk3';
|
||||||
|
|
||||||
const { label, pollingInterval, onIcon, offIcon, onLabel, offLabel, rightClick, middleClick, scrollUp, scrollDown } =
|
const { label, onIcon, offIcon, onLabel, offLabel, rightClick, middleClick, scrollUp, scrollDown } =
|
||||||
options.bar.customModules.hypridle;
|
options.bar.customModules.hypridle;
|
||||||
|
|
||||||
const dummyVar = Variable(undefined);
|
function toggleInhibit(): void {
|
||||||
|
idleInhibit.set(!idleInhibit.get());
|
||||||
checkIdleStatus();
|
}
|
||||||
|
|
||||||
const idleStatusPoller = new FunctionPoller<undefined, []>(dummyVar, [], bind(pollingInterval), checkIdleStatus);
|
|
||||||
|
|
||||||
idleStatusPoller.initialize('hypridle');
|
|
||||||
|
|
||||||
const throttledToggleIdle = throttleInput(() => toggleIdle(isActive), 1000);
|
|
||||||
|
|
||||||
export const Hypridle = (): BarBoxChild => {
|
export const Hypridle = (): BarBoxChild => {
|
||||||
const iconBinding = Variable.derive([bind(isActive), bind(onIcon), bind(offIcon)], (active, onIcn, offIcn) => {
|
const iconBinding = Variable.derive([bind(idleInhibit), bind(onIcon), bind(offIcon)], (active, onIcn, offIcn) => {
|
||||||
return active ? onIcn : offIcn;
|
return active ? onIcn : offIcn;
|
||||||
});
|
});
|
||||||
const labelBinding = Variable.derive([bind(isActive), bind(onLabel), bind(offLabel)], (active, onLbl, offLbl) => {
|
|
||||||
return active ? onLbl : offLbl;
|
const labelBinding = Variable.derive(
|
||||||
});
|
[bind(idleInhibit), bind(onLabel), bind(offLabel)],
|
||||||
|
(active, onLbl, offLbl) => {
|
||||||
|
return active ? onLbl : offLbl;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
const hypridleModule = Module({
|
const hypridleModule = Module({
|
||||||
textIcon: iconBinding(),
|
textIcon: iconBinding(),
|
||||||
tooltipText: bind(isActive).as((active) => `Hypridle ${active ? 'enabled' : 'disabled'}`),
|
tooltipText: bind(idleInhibit).as((active) => `Idle Inhibitor: ${active ? 'Enabled' : 'Disabled'}`),
|
||||||
boxClass: 'hypridle',
|
boxClass: 'hypridle',
|
||||||
label: labelBinding(),
|
label: labelBinding(),
|
||||||
showLabelBinding: bind(label),
|
showLabelBinding: bind(label),
|
||||||
@@ -40,7 +36,7 @@ export const Hypridle = (): BarBoxChild => {
|
|||||||
inputHandler(self, {
|
inputHandler(self, {
|
||||||
onPrimaryClick: {
|
onPrimaryClick: {
|
||||||
fn: () => {
|
fn: () => {
|
||||||
throttledToggleIdle();
|
toggleInhibit();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
onSecondaryClick: {
|
onSecondaryClick: {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ResourceLabelType } from 'src/lib/types/bar';
|
import { ResourceLabelType } from 'src/lib/types/bar';
|
||||||
import { GenericResourceData, Postfix, UpdateHandlers } from 'src/lib/types/customModules/generic';
|
import { GenericResourceData, Postfix, UpdateHandlers } from 'src/lib/types/customModules/generic';
|
||||||
import { InputHandlerEvents, RunAsyncCommand } from 'src/lib/types/customModules/utils';
|
import { InputHandlerEventArgs, InputHandlerEvents, RunAsyncCommand } from 'src/lib/types/customModules/utils';
|
||||||
import { ThrottleFn } from 'src/lib/types/utils';
|
import { ThrottleFn } from 'src/lib/types/utils';
|
||||||
import { bind, Binding, execAsync, Variable } from 'astal';
|
import { bind, Binding, execAsync, Variable } from 'astal';
|
||||||
import { openMenu } from 'src/components/bar/utils/menu';
|
import { openMenu } from 'src/components/bar/utils/menu';
|
||||||
@@ -56,6 +56,15 @@ export const runAsyncCommand: RunAsyncCommand = (cmd, events, fn, postInputUpdat
|
|||||||
.catch((err) => console.error(`Error running command "${cmd}": ${err})`));
|
.catch((err) => console.error(`Error running command "${cmd}": ${err})`));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* NOTE: Added a throttle since spamming a button yields duplicate events
|
||||||
|
* which undo the toggle.
|
||||||
|
*/
|
||||||
|
const throttledAsyncCommand = throttleInput(
|
||||||
|
(cmd, events, fn, postInputUpdater?: Variable<boolean>) => runAsyncCommand(cmd, events, fn, postInputUpdater),
|
||||||
|
50,
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic throttle function to limit the rate at which a function can be called.
|
* Generic throttle function to limit the rate at which a function can be called.
|
||||||
*
|
*
|
||||||
@@ -90,7 +99,7 @@ export function throttleInput<T extends ThrottleFn>(func: T, limit: number): T {
|
|||||||
*/
|
*/
|
||||||
export const throttledScrollHandler = (interval: number): ThrottleFn =>
|
export const throttledScrollHandler = (interval: number): ThrottleFn =>
|
||||||
throttleInput((cmd: string, args, fn, postInputUpdater) => {
|
throttleInput((cmd: string, args, fn, postInputUpdater) => {
|
||||||
runAsyncCommand(cmd, args, fn, postInputUpdater);
|
throttledAsyncCommand(cmd, args, fn, postInputUpdater);
|
||||||
}, 200 / interval);
|
}, 200 / interval);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -114,7 +123,7 @@ export const inputHandler = (
|
|||||||
}: InputHandlerEvents,
|
}: InputHandlerEvents,
|
||||||
postInputUpdater?: Variable<boolean>,
|
postInputUpdater?: Variable<boolean>,
|
||||||
): void => {
|
): void => {
|
||||||
const sanitizeInput = (input: Variable<string>): string => {
|
const sanitizeInput = (input?: Variable<string> | Variable<string>): string => {
|
||||||
if (input === undefined) {
|
if (input === undefined) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
@@ -126,34 +135,34 @@ export const inputHandler = (
|
|||||||
const throttledHandler = throttledScrollHandler(interval);
|
const throttledHandler = throttledScrollHandler(interval);
|
||||||
|
|
||||||
const disconnectPrimaryClick = onPrimaryClick(self, (clicked: GtkWidget, event: Gdk.Event) => {
|
const disconnectPrimaryClick = onPrimaryClick(self, (clicked: GtkWidget, event: Gdk.Event) => {
|
||||||
runAsyncCommand(
|
throttledAsyncCommand(
|
||||||
sanitizeInput(onPrimaryClickInput?.cmd || dummyVar),
|
sanitizeInput(onPrimaryClickInput?.cmd || dummyVar),
|
||||||
{ clicked, event },
|
{ clicked, event },
|
||||||
onPrimaryClickInput.fn,
|
onPrimaryClickInput?.fn,
|
||||||
postInputUpdater,
|
postInputUpdater,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const disconnectSecondaryClick = onSecondaryClick(self, (clicked: GtkWidget, event: Gdk.Event) => {
|
const disconnectSecondaryClick = onSecondaryClick(self, (clicked: GtkWidget, event: Gdk.Event) => {
|
||||||
runAsyncCommand(
|
throttledAsyncCommand(
|
||||||
sanitizeInput(onSecondaryClickInput?.cmd || dummyVar),
|
sanitizeInput(onSecondaryClickInput?.cmd || dummyVar),
|
||||||
{ clicked, event },
|
{ clicked, event },
|
||||||
onSecondaryClickInput.fn,
|
onSecondaryClickInput?.fn,
|
||||||
postInputUpdater,
|
postInputUpdater,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const disconnectMiddleClick = onMiddleClick(self, (clicked: GtkWidget, event: Gdk.Event) => {
|
const disconnectMiddleClick = onMiddleClick(self, (clicked: GtkWidget, event: Gdk.Event) => {
|
||||||
runAsyncCommand(
|
throttledAsyncCommand(
|
||||||
sanitizeInput(onMiddleClickInput?.cmd || dummyVar),
|
sanitizeInput(onMiddleClickInput?.cmd || dummyVar),
|
||||||
{ clicked, event },
|
{ clicked, event },
|
||||||
onMiddleClickInput.fn,
|
onMiddleClickInput?.fn,
|
||||||
postInputUpdater,
|
postInputUpdater,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const id = self.connect('scroll-event', (self: GtkWidget, event: Gdk.Event) => {
|
const id = self.connect('scroll-event', (self: GtkWidget, event: Gdk.Event) => {
|
||||||
const handleScroll = (input?: { cmd: Variable<string>; fn: (output: string) => void }): void => {
|
const handleScroll = (input?: InputHandlerEventArgs): void => {
|
||||||
if (input) {
|
if (input) {
|
||||||
throttledHandler(sanitizeInput(input.cmd), { clicked: self, event }, input.fn, postInputUpdater);
|
throttledHandler(sanitizeInput(input.cmd), { clicked: self, event }, input.fn, postInputUpdater);
|
||||||
}
|
}
|
||||||
@@ -178,8 +187,8 @@ export const inputHandler = (
|
|||||||
|
|
||||||
updateHandlers();
|
updateHandlers();
|
||||||
|
|
||||||
const sanitizeVariable = (someVar: Variable<string> | undefined): Binding<string> => {
|
const sanitizeVariable = (someVar?: Variable<string>): Binding<string> => {
|
||||||
if (someVar === undefined || typeof someVar.bind !== 'function') {
|
if (someVar === undefined) {
|
||||||
return bind(dummyVar);
|
return bind(dummyVar);
|
||||||
}
|
}
|
||||||
return bind(someVar);
|
return bind(someVar);
|
||||||
@@ -188,11 +197,11 @@ export const inputHandler = (
|
|||||||
Variable.derive(
|
Variable.derive(
|
||||||
[
|
[
|
||||||
bind(scrollSpeed),
|
bind(scrollSpeed),
|
||||||
sanitizeVariable(onPrimaryClickInput),
|
sanitizeVariable(onPrimaryClickInput?.cmd),
|
||||||
sanitizeVariable(onSecondaryClickInput),
|
sanitizeVariable(onSecondaryClickInput?.cmd),
|
||||||
sanitizeVariable(onMiddleClickInput),
|
sanitizeVariable(onMiddleClickInput?.cmd),
|
||||||
sanitizeVariable(onScrollUpInput),
|
sanitizeVariable(onScrollUpInput?.cmd),
|
||||||
sanitizeVariable(onScrollDownInput),
|
sanitizeVariable(onScrollDownInput?.cmd),
|
||||||
],
|
],
|
||||||
() => {
|
() => {
|
||||||
const handlers = updateHandlers();
|
const handlers = updateHandlers();
|
||||||
|
|||||||
1
src/globals.d.ts
vendored
1
src/globals.d.ts
vendored
@@ -15,6 +15,7 @@ declare global {
|
|||||||
var globalWeatherVar: Variable<Weather>;
|
var globalWeatherVar: Variable<Weather>;
|
||||||
var options: Options;
|
var options: Options;
|
||||||
var removingNotifications: Variable<boolean>;
|
var removingNotifications: Variable<boolean>;
|
||||||
|
var idleInhibit: Variable<boolean>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export {};
|
export {};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { App } from 'astal/gtk3';
|
import { App } from 'astal/gtk3';
|
||||||
import options from '../options';
|
import options from '../options';
|
||||||
import { BarLayouts } from 'src/lib/types/options';
|
import { BarLayouts } from 'src/lib/types/options';
|
||||||
|
import { Variable } from 'astal';
|
||||||
|
|
||||||
globalThis.isWindowVisible = (windowName: string): boolean => {
|
globalThis.isWindowVisible = (windowName: string): boolean => {
|
||||||
const appWindow = App.get_window(windowName);
|
const appWindow = App.get_window(windowName);
|
||||||
@@ -22,3 +23,5 @@ globalThis.setLayout = (layout: BarLayouts): string => {
|
|||||||
return `Failed to set layout: ${error}`;
|
return `Failed to set layout: ${error}`;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
globalThis.idleInhibit = Variable(false);
|
||||||
|
|||||||
17
src/lib/types/customModules/utils.d.ts
vendored
17
src/lib/types/customModules/utils.d.ts
vendored
@@ -1,12 +1,17 @@
|
|||||||
|
import { Variable } from 'astal';
|
||||||
|
import { Opt } from 'src/lib/option';
|
||||||
import { Binding } from 'src/lib/utils';
|
import { Binding } from 'src/lib/utils';
|
||||||
import { Variable } from 'types/variable';
|
|
||||||
|
|
||||||
|
export type InputHandlerEventArgs = {
|
||||||
|
cmd?: Opt<string> | Variable<string>;
|
||||||
|
fn?: (output: string) => void;
|
||||||
|
};
|
||||||
export type InputHandlerEvents = {
|
export type InputHandlerEvents = {
|
||||||
onPrimaryClick?: Binding;
|
onPrimaryClick?: InputHandlerEventArgs;
|
||||||
onSecondaryClick?: Binding;
|
onSecondaryClick?: InputHandlerEventArgs;
|
||||||
onMiddleClick?: Binding;
|
onMiddleClick?: InputHandlerEventArgs;
|
||||||
onScrollUp?: Binding;
|
onScrollUp?: InputHandlerEventArgs;
|
||||||
onScrollDown?: Binding;
|
onScrollDown?: InputHandlerEventArgs;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type RunAsyncCommand = (
|
export type RunAsyncCommand = (
|
||||||
|
|||||||
@@ -1172,8 +1172,8 @@ const options = mkOptions(CONFIG, {
|
|||||||
},
|
},
|
||||||
hypridle: {
|
hypridle: {
|
||||||
label: opt(true),
|
label: opt(true),
|
||||||
onIcon: opt(''),
|
onIcon: opt(''),
|
||||||
offIcon: opt(''),
|
offIcon: opt(''),
|
||||||
onLabel: opt('On'),
|
onLabel: opt('On'),
|
||||||
offLabel: opt('Off'),
|
offLabel: opt('Off'),
|
||||||
pollingInterval: opt(1000 * 2),
|
pollingInterval: opt(1000 * 2),
|
||||||
|
|||||||
Reference in New Issue
Block a user