diff --git a/customModules/cpu/index.ts b/customModules/cpu/index.ts index 1eb8ea73c..73f96ed6a 100644 --- a/customModules/cpu/index.ts +++ b/customModules/cpu/index.ts @@ -3,15 +3,14 @@ import options from 'options'; // Module initializer import { module } from '../module'; -// import { CpuData } from "lib/types/customModules/cpu"; import Button from 'types/widgets/button'; -import Gtk from 'types/@girs/gtk-3.0/gtk-3.0'; // Utility Methods import { inputHandler } from 'customModules/utils'; import { computeCPU } from './computeCPU'; import { pollVariable } from 'customModules/PollVar'; -import { Module } from 'lib/types/bar'; +import { BarBoxChild } from 'lib/types/bar'; +import { Attribute, Child } from 'lib/types/widget'; // All the user configurable options for the cpu module that are needed const { label, round, leftClick, rightClick, middleClick, scrollUp, scrollDown, pollingInterval } = @@ -30,7 +29,7 @@ pollVariable( computeCPU, ); -export const Cpu = (): Module => { +export const Cpu = (): BarBoxChild => { const renderLabel = (cpuUsg: number, rnd: boolean): string => { return rnd ? `${Math.round(cpuUsg)}%` : `${cpuUsg.toFixed(2)}%`; }; @@ -44,7 +43,7 @@ export const Cpu = (): Module => { boxClass: 'cpu', showLabelBinding: label.bind('value'), props: { - setup: (self: Button) => { + setup: (self: Button) => { inputHandler(self, { onPrimaryClick: { cmd: leftClick, diff --git a/customModules/kblayout/index.ts b/customModules/kblayout/index.ts index 479bc7e77..8c566e5a6 100644 --- a/customModules/kblayout/index.ts +++ b/customModules/kblayout/index.ts @@ -8,12 +8,13 @@ import Gtk from 'types/@girs/gtk-3.0/gtk-3.0'; import Button from 'types/widgets/button'; import Label from 'types/widgets/label'; import { getKeyboardLayout } from './getLayout'; -import { Module } from 'lib/types/bar'; +import { BarBoxChild } from 'lib/types/bar'; +import { Attribute, Child } from 'lib/types/widget'; const { label, labelType, icon, leftClick, rightClick, middleClick, scrollUp, scrollDown } = options.bar.customModules.kbLayout; -export const KbInput = (): Module => { +export const KbInput = (): BarBoxChild => { const keyboardModule = module({ textIcon: icon.bind('value'), tooltipText: '', @@ -46,7 +47,7 @@ export const KbInput = (): Module => { boxClass: 'kblayout', showLabelBinding: label.bind('value'), props: { - setup: (self: Button) => { + setup: (self: Button) => { inputHandler(self, { onPrimaryClick: { cmd: leftClick, diff --git a/customModules/netstat/index.ts b/customModules/netstat/index.ts index fce6f1c52..abfe2ca19 100644 --- a/customModules/netstat/index.ts +++ b/customModules/netstat/index.ts @@ -2,13 +2,13 @@ import options from 'options'; import { module } from '../module'; import { inputHandler } from 'customModules/utils'; import { computeNetwork } from './computeNetwork'; -import { Module, NetstatLabelType } from 'lib/types/bar'; -import Gtk from 'types/@girs/gtk-3.0/gtk-3.0'; +import { BarBoxChild, NetstatLabelType } 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'; const { label, @@ -46,7 +46,7 @@ pollVariable( rateUnit, ); -export const Netstat = (): Module => { +export const Netstat = (): BarBoxChild => { const renderNetworkLabel = (lblType: NetstatLabelType, network: NetworkResourceData): string => { switch (lblType) { case 'in': @@ -70,7 +70,7 @@ export const Netstat = (): Module => { boxClass: 'netstat', showLabelBinding: label.bind('value'), props: { - setup: (self: Button) => { + setup: (self: Button) => { inputHandler(self, { onPrimaryClick: { cmd: leftClick, diff --git a/customModules/power/index.ts b/customModules/power/index.ts index 217057184..da678ad1c 100644 --- a/customModules/power/index.ts +++ b/customModules/power/index.ts @@ -2,19 +2,19 @@ import options from 'options'; import { module } from '../module'; import { inputHandler } from 'customModules/utils'; -import Gtk from 'types/@girs/gtk-3.0/gtk-3.0'; import Button from 'types/widgets/button'; -import { Module } from 'lib/types/bar'; +import { Attribute, Child } from 'lib/types/widget'; +import { BarBoxChild } from 'lib/types/bar'; const { icon, leftClick, rightClick, middleClick, scrollUp, scrollDown } = options.bar.customModules.power; -export const Power = (): Module => { +export const Power = (): BarBoxChild => { const powerModule = module({ tooltipText: 'Power Menu', textIcon: icon.bind('value'), boxClass: 'powermodule', props: { - setup: (self: Button) => { + setup: (self: Button) => { inputHandler(self, { onPrimaryClick: { cmd: leftClick, diff --git a/customModules/ram/index.ts b/customModules/ram/index.ts index 58fb0755d..c78d8f5e5 100644 --- a/customModules/ram/index.ts +++ b/customModules/ram/index.ts @@ -6,18 +6,18 @@ import { module } from '../module'; // Types import { GenericResourceData } from 'lib/types/customModules/generic'; import Button from 'types/widgets/button'; -import Gtk from 'types/@girs/gtk-3.0/gtk-3.0'; // Helper Methods import { calculateRamUsage } from './computeRam'; // Utility Methods import { formatTooltip, inputHandler, renderResourceLabel } from 'customModules/utils'; -import { Module, ResourceLabelType } from 'lib/types/bar'; +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'; // All the user configurable options for the ram module that are needed const { label, labelType, round, leftClick, rightClick, middleClick, pollingInterval } = options.bar.customModules.ram; @@ -27,7 +27,7 @@ const ramUsage = Variable(defaultRamData); pollVariable(ramUsage, [round.bind('value')], pollingInterval.bind('value'), calculateRamUsage, round); -export const Ram = (): Module => { +export const Ram = (): BarBoxChild => { const ramModule = module({ textIcon: '', label: Utils.merge( @@ -44,7 +44,7 @@ export const Ram = (): Module => { boxClass: 'ram', showLabelBinding: label.bind('value'), props: { - setup: (self: Button) => { + setup: (self: Button) => { inputHandler(self, { onPrimaryClick: { cmd: leftClick, diff --git a/customModules/storage/index.ts b/customModules/storage/index.ts index eed1f0174..9cfeb85dc 100644 --- a/customModules/storage/index.ts +++ b/customModules/storage/index.ts @@ -3,12 +3,12 @@ import { module } from '../module'; import { formatTooltip, inputHandler, renderResourceLabel } from 'customModules/utils'; import { computeStorage } from './computeStorage'; -import { Module, ResourceLabelType } from 'lib/types/bar'; +import { BarBoxChild, ResourceLabelType } from 'lib/types/bar'; import { GenericResourceData } from 'lib/types/customModules/generic'; -import Gtk from 'types/@girs/gtk-3.0/gtk-3.0'; 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'; const { label, labelType, icon, round, leftClick, rightClick, middleClick, pollingInterval } = options.bar.customModules.storage; @@ -19,7 +19,7 @@ const storageUsage = Variable(defaultStorageData); pollVariable(storageUsage, [round.bind('value')], pollingInterval.bind('value'), computeStorage, round); -export const Storage = (): Module => { +export const Storage = (): BarBoxChild => { const storageModule = module({ textIcon: icon.bind('value'), label: Utils.merge( @@ -34,7 +34,7 @@ export const Storage = (): Module => { boxClass: 'storage', showLabelBinding: label.bind('value'), props: { - setup: (self: Button) => { + setup: (self: Button) => { inputHandler(self, { onPrimaryClick: { cmd: leftClick, diff --git a/customModules/updates/index.ts b/customModules/updates/index.ts index c427fd3a6..4be5ee8c7 100644 --- a/customModules/updates/index.ts +++ b/customModules/updates/index.ts @@ -2,11 +2,11 @@ import options from 'options'; import { module } from '../module'; import { inputHandler } from 'customModules/utils'; -import Gtk from 'types/@girs/gtk-3.0/gtk-3.0'; import Button from 'types/widgets/button'; import { Variable as VariableType } from 'types/variable'; import { pollVariableBash } from 'customModules/PollVar'; -import { Module } from 'lib/types/bar'; +import { Attribute, Child } from 'lib/types/widget'; +import { BarBoxChild } from 'lib/types/bar'; const { updateCommand, @@ -36,7 +36,7 @@ pollVariableBash( processUpdateCount, ); -export const Updates = (): Module => { +export const Updates = (): BarBoxChild => { const updatesModule = module({ textIcon: icon.bind('value'), tooltipText: pendingUpdates.bind('value').as((v) => `${v} updates available`), @@ -44,7 +44,7 @@ export const Updates = (): Module => { label: pendingUpdates.bind('value'), showLabelBinding: label.bind('value'), props: { - setup: (self: Button) => { + setup: (self: Button) => { inputHandler(self, { onPrimaryClick: { cmd: leftClick, diff --git a/customModules/utils.ts b/customModules/utils.ts index 20679ab3a..b68258ede 100644 --- a/customModules/utils.ts +++ b/customModules/utils.ts @@ -1,23 +1,18 @@ import { ResourceLabelType } from 'lib/types/bar'; import { GenericResourceData, Postfix } from 'lib/types/customModules/generic'; -import { InputHandlerEvents } from 'lib/types/customModules/utils'; +import { InputHandlerEvents, RunAsyncCommand } from 'lib/types/customModules/utils'; import { ThrottleFn, ThrottleFnCallback } from 'lib/types/utils'; -import { GtkWidget } from 'lib/types/widget'; +import { Attribute, Child, EventArgs } from 'lib/types/widget'; import { Binding } from 'lib/utils'; import { openMenu } from 'modules/bar/utils'; import options from 'options'; import Gdk from 'types/@girs/gdk-3.0/gdk-3.0'; -import Gtk from 'types/@girs/gtk-3.0/gtk-3.0'; import { Variable as VariableType } from 'types/variable'; import Button from 'types/widgets/button'; const { scrollSpeed } = options.bar.customModules; -export const runAsyncCommand = ( - cmd: string, - fn: (output: string) => void, - events: { clicked: Button; event: Gdk.Event }, -): void => { +export const runAsyncCommand: RunAsyncCommand = (cmd, events, fn): void => { if (cmd.startsWith('menu:')) { const menuName = cmd.split(':')[1].trim().toLowerCase(); openMenu(events.clicked, events.event, `${menuName}menu`); @@ -48,20 +43,14 @@ export function throttle(func: T, limit: number): T { } export const throttledScrollHandler = (interval: number): ThrottleFn => - throttle((cmd: string, fn: ThrottleFnCallback) => { - Utils.execAsync(`bash -c "${cmd}"`) - .then((output) => { - if (fn !== undefined) { - fn(output); - } - }) - .catch((err) => console.error(`Error running command "${cmd}": ${err}`)); + throttle((cmd: string, events: EventArgs, fn: ThrottleFnCallback) => { + runAsyncCommand(cmd, events, fn); }, 200 / interval); const dummyVar = Variable(''); export const inputHandler = ( - self: Button, + self: Button, { onPrimaryClick, onSecondaryClick, onMiddleClick, onScrollUp, onScrollDown }: InputHandlerEvents, ): void => { const sanitizeInput = (input: VariableType): string => { @@ -75,19 +64,20 @@ export const inputHandler = ( const interval = scrollSpeed.value; const throttledHandler = throttledScrollHandler(interval); - self.on_primary_click = (clicked: Button, event: Gdk.Event): void => - runAsyncCommand(sanitizeInput(onPrimaryClick?.cmd || dummyVar), onPrimaryClick.fn, { clicked, event }); + self.on_primary_click = (clicked: Button, event: Gdk.Event): void => + runAsyncCommand(sanitizeInput(onPrimaryClick?.cmd || dummyVar), { clicked, event }, onPrimaryClick.fn); - self.on_secondary_click = (clicked: Button, event: Gdk.Event): void => - runAsyncCommand(sanitizeInput(onSecondaryClick?.cmd || dummyVar), onSecondaryClick.fn, { clicked, event }); + self.on_secondary_click = (clicked: Button, event: Gdk.Event): void => + runAsyncCommand(sanitizeInput(onSecondaryClick?.cmd || dummyVar), { clicked, event }, onSecondaryClick.fn); - self.on_middle_click = (clicked: Button, event: Gdk.Event): void => - runAsyncCommand(sanitizeInput(onMiddleClick?.cmd || dummyVar), onMiddleClick.fn, { clicked, event }); + self.on_middle_click = (clicked: Button, event: Gdk.Event): void => + runAsyncCommand(sanitizeInput(onMiddleClick?.cmd || dummyVar), { clicked, event }, onMiddleClick.fn); - self.on_scroll_up = (): void => throttledHandler(sanitizeInput(onScrollUp?.cmd || dummyVar), onScrollUp.fn); + self.on_scroll_up = (clicked: Button, event: Gdk.Event): void => + throttledHandler(sanitizeInput(onScrollUp?.cmd || dummyVar), { clicked, event }, onScrollUp.fn); - self.on_scroll_down = (): void => - throttledHandler(sanitizeInput(onScrollDown?.cmd || dummyVar), onScrollDown.fn); + self.on_scroll_down = (clicked: Button, event: Gdk.Event): void => + throttledHandler(sanitizeInput(onScrollDown?.cmd || dummyVar), { clicked, event }, onScrollDown.fn); }; // Initial setup of event handlers diff --git a/customModules/weather/index.ts b/customModules/weather/index.ts index 9cd4ff1a1..b40995c29 100644 --- a/customModules/weather/index.ts +++ b/customModules/weather/index.ts @@ -2,14 +2,14 @@ import options from 'options'; import { module } from '../module'; import { inputHandler } from 'customModules/utils'; -import Gtk from 'types/@girs/gtk-3.0/gtk-3.0'; import Button from 'types/widgets/button'; import { getWeatherStatusTextIcon, globalWeatherVar } from 'globals/weather'; -import { Module } from 'lib/types/bar'; +import { Attribute, Child } from 'lib/types/widget'; +import { BarBoxChild } from 'lib/types/bar'; const { label, unit, leftClick, rightClick, middleClick, scrollUp, scrollDown } = options.bar.customModules.weather; -export const Weather = (): Module => { +export const Weather = (): BarBoxChild => { const weatherModule = module({ textIcon: Utils.merge([globalWeatherVar.bind('value')], (wthr) => { const weatherStatusIcon = getWeatherStatusTextIcon(wthr); @@ -26,7 +26,7 @@ export const Weather = (): Module => { }), showLabelBinding: label.bind('value'), props: { - setup: (self: Button) => { + setup: (self: Button) => { inputHandler(self, { onPrimaryClick: { cmd: leftClick, diff --git a/lib/types/bar.d.ts b/lib/types/bar.d.ts index 01176aef9..13033d48a 100644 --- a/lib/types/bar.d.ts +++ b/lib/types/bar.d.ts @@ -1,7 +1,7 @@ import { Binding, Connectable } from 'types/service'; import { Variable } from 'types/variable'; import Box from 'types/widgets/box'; -import Button from 'types/widgets/button'; +import Button, { ButtonProps } from 'types/widgets/button'; import Label from 'types/widgets/label'; import { Attribute, Child } from './widget'; @@ -10,7 +10,9 @@ export type BarBoxChild = { isVisible?: boolean; isVis?: Variable; boxClass: string; -} & ButtonProps; + tooltip_text?: string | Binding; + props: ButtonProps; +}; export type SelfButton = Button; diff --git a/lib/types/customModules/utils.d.ts b/lib/types/customModules/utils.d.ts index 9764bc8e2..14ccf9065 100644 --- a/lib/types/customModules/utils.d.ts +++ b/lib/types/customModules/utils.d.ts @@ -7,3 +7,5 @@ export type InputHandlerEvents = { onScrollUp?: Binding; onScrollDown?: Binding; }; + +export type RunAsyncCommand = (cmd: string, args: EventArgs, fn?: (output: string) => void) => void; diff --git a/lib/types/utils.d.ts b/lib/types/utils.d.ts index 884d339e8..b35af4679 100644 --- a/lib/types/utils.d.ts +++ b/lib/types/utils.d.ts @@ -1,6 +1,7 @@ import { substitutes } from 'lib/icons'; +import { EventArgs } from './widget'; type SubstituteKeys = keyof typeof substitutes; -export type ThrottleFn = (cmd: string, fn: ((output: string) => void) | undefined) => void; +export type ThrottleFn = (cmd: string, args: EventArgs, fn?: (output: string) => void) => void; export type ThrottleFnCallback = ((output: string) => void) | undefined; diff --git a/lib/types/widget.d.ts b/lib/types/widget.d.ts index 57dfd0b25..ebb09a48b 100644 --- a/lib/types/widget.d.ts +++ b/lib/types/widget.d.ts @@ -26,3 +26,4 @@ export type GLabel = Gtk.Label; export type GCenterBox = Gtk.Box; export type EventHandler = (self: Self, event: Gdk.Event) => boolean | unknown; +export type EventArgs = { clicked: Button; event: Gdk.Event }; diff --git a/modules/bar/battery/index.ts b/modules/bar/battery/index.ts index 98ed65075..95799114d 100644 --- a/modules/bar/battery/index.ts +++ b/modules/bar/battery/index.ts @@ -4,9 +4,10 @@ import { openMenu } from '../utils.js'; import options from 'options'; import { BarBoxChild } from 'lib/types/bar.js'; import Button from 'types/widgets/button.js'; -import { Child } from 'lib/types/widget.js'; +import { Attribute, Child } from 'lib/types/widget.js'; +import { runAsyncCommand, throttledScrollHandler } from 'customModules/utils.js'; -const { label: show_label } = options.bar.battery; +const { label: show_label, rightClick, middleClick, scrollUp, scrollDown } = options.bar.battery; const BatteryLabel = (): BarBoxChild => { const isVis = Variable(battery.available); @@ -92,7 +93,25 @@ const BatteryLabel = (): BarBoxChild => { isVis, boxClass: 'battery', props: { - on_primary_click: (clicked: Button, event: Gdk.Event): void => { + setup: (self: Button): void => { + self.hook(options.bar.scrollSpeed, () => { + const throttledHandler = throttledScrollHandler(options.bar.scrollSpeed.value); + + self.on_secondary_click = (clicked: Button, event: Gdk.Event): void => { + runAsyncCommand(rightClick.value, { clicked, event }); + }; + self.on_middle_click = (clicked: Button, event: Gdk.Event): void => { + runAsyncCommand(middleClick.value, { clicked, event }); + }; + self.on_scroll_up = (clicked: Button, event: Gdk.Event): void => { + throttledHandler(scrollUp.value, { clicked, event }); + }; + self.on_scroll_down = (clicked: Button, event: Gdk.Event): void => { + throttledHandler(scrollDown.value, { clicked, event }); + }; + }); + }, + onPrimaryClick: (clicked: Button, event: Gdk.Event): void => { openMenu(clicked, event, 'energymenu'); }, }, diff --git a/modules/bar/bluetooth/index.ts b/modules/bar/bluetooth/index.ts index c9cbb4583..5aa5e9b58 100644 --- a/modules/bar/bluetooth/index.ts +++ b/modules/bar/bluetooth/index.ts @@ -4,9 +4,10 @@ import options from 'options'; import { openMenu } from '../utils.js'; import { BarBoxChild } from 'lib/types/bar.js'; import Button from 'types/widgets/button.js'; -import { Child } from 'lib/types/widget.js'; +import { Attribute, Child } from 'lib/types/widget.js'; +import { runAsyncCommand, throttledScrollHandler } from 'customModules/utils.js'; -const { label } = options.bar.bluetooth; +const { label, rightClick, middleClick, scrollDown, scrollUp } = options.bar.bluetooth; const Bluetooth = (): BarBoxChild => { const btIcon = Widget.Label({ @@ -45,7 +46,25 @@ const Bluetooth = (): BarBoxChild => { isVisible: true, boxClass: 'bluetooth', props: { - on_primary_click: (clicked: Button, event: Gdk.Event): void => { + setup: (self: Button): void => { + self.hook(options.bar.scrollSpeed, () => { + const throttledHandler = throttledScrollHandler(options.bar.scrollSpeed.value); + + self.on_secondary_click = (clicked: Button, event: Gdk.Event): void => { + runAsyncCommand(rightClick.value, { clicked, event }); + }; + self.on_middle_click = (clicked: Button, event: Gdk.Event): void => { + runAsyncCommand(middleClick.value, { clicked, event }); + }; + self.on_scroll_up = (clicked: Button, event: Gdk.Event): void => { + throttledHandler(scrollUp.value, { clicked, event }); + }; + self.on_scroll_down = (clicked: Button, event: Gdk.Event): void => { + throttledHandler(scrollDown.value, { clicked, event }); + }; + }); + }, + on_primary_click: (clicked: Button, event: Gdk.Event): void => { openMenu(clicked, event, 'bluetoothmenu'); }, }, diff --git a/modules/bar/clock/index.ts b/modules/bar/clock/index.ts index c55a5051b..351868594 100644 --- a/modules/bar/clock/index.ts +++ b/modules/bar/clock/index.ts @@ -5,8 +5,10 @@ import options from 'options'; import { DateTime } from 'types/@girs/glib-2.0/glib-2.0.cjs'; import { BarBoxChild } from 'lib/types/bar.js'; import Button from 'types/widgets/button.js'; -import { Child } from 'lib/types/widget.js'; -const { format, icon, showIcon, showTime } = options.bar.clock; +import { Attribute, Child } from 'lib/types/widget.js'; +import { runAsyncCommand, throttledScrollHandler } from 'customModules/utils.js'; + +const { format, icon, showIcon, showTime, rightClick, middleClick, scrollUp, scrollDown } = options.bar.clock; const { style } = options.theme.bar.buttons; const date = Variable(GLib.DateTime.new_now_local(), { @@ -53,7 +55,25 @@ const Clock = (): BarBoxChild => { isVisible: true, boxClass: 'clock', props: { - on_primary_click: (clicked: Button, event: Gdk.Event): void => { + setup: (self: Button): void => { + self.hook(options.bar.scrollSpeed, () => { + const throttledHandler = throttledScrollHandler(options.bar.scrollSpeed.value); + + self.on_secondary_click = (clicked: Button, event: Gdk.Event): void => { + runAsyncCommand(rightClick.value, { clicked, event }); + }; + self.on_middle_click = (clicked: Button, event: Gdk.Event): void => { + runAsyncCommand(middleClick.value, { clicked, event }); + }; + self.on_scroll_up = (clicked: Button, event: Gdk.Event): void => { + throttledHandler(scrollUp.value, { clicked, event }); + }; + self.on_scroll_down = (clicked: Button, event: Gdk.Event): void => { + throttledHandler(scrollDown.value, { clicked, event }); + }; + }); + }, + on_primary_click: (clicked: Button, event: Gdk.Event): void => { openMenu(clicked, event, 'calendarmenu'); }, }, diff --git a/modules/bar/media/index.ts b/modules/bar/media/index.ts index 7266a5c17..1b981baf6 100644 --- a/modules/bar/media/index.ts +++ b/modules/bar/media/index.ts @@ -5,9 +5,11 @@ import options from 'options'; import { getCurrentPlayer } from 'lib/shared/media.js'; import { BarBoxChild } from 'lib/types/bar.js'; import Button from 'types/widgets/button.js'; -import { Child } from 'lib/types/widget.js'; +import { Attribute, Child } from 'lib/types/widget.js'; +import { runAsyncCommand } from 'customModules/utils.js'; -const { show_artist, truncation, truncation_size, show_label, show_active_only } = options.bar.media; +const { show_artist, truncation, truncation_size, show_label, show_active_only, rightClick, middleClick } = + options.bar.media; const Media = (): BarBoxChild => { const activePlayer = Variable(mpris.players[0]); @@ -92,13 +94,18 @@ const Media = (): BarBoxChild => { }), isVis, boxClass: 'media', - name: 'media', props: { on_scroll_up: () => activePlayer.value?.next(), on_scroll_down: () => activePlayer.value?.previous(), - on_primary_click: (clicked: Button, event: Gdk.Event): void => { + on_primary_click: (clicked: Button, event: Gdk.Event): void => { openMenu(clicked, event, 'mediamenu'); }, + onSecondaryClick: (clicked: Button, event: Gdk.Event): void => { + runAsyncCommand(rightClick.value, { clicked, event }); + }, + onMiddleClick: (clicked: Button, event: Gdk.Event): void => { + runAsyncCommand(middleClick.value, { clicked, event }); + }, }, }; }; diff --git a/modules/bar/menu/index.ts b/modules/bar/menu/index.ts index 5612dc4d5..5c55bfb58 100644 --- a/modules/bar/menu/index.ts +++ b/modules/bar/menu/index.ts @@ -3,7 +3,10 @@ import { openMenu } from '../utils.js'; import options from 'options'; import { BarBoxChild } from 'lib/types/bar.js'; import Button from 'types/widgets/button.js'; -import { Child } from 'lib/types/widget.js'; +import { Attribute, Child } from 'lib/types/widget.js'; +import { runAsyncCommand, throttledScrollHandler } from 'customModules/utils.js'; + +const { rightClick, middleClick, scrollUp, scrollDown } = options.bar.launcher; const Menu = (): BarBoxChild => { return { @@ -25,9 +28,27 @@ const Menu = (): BarBoxChild => { isVisible: true, boxClass: 'dashboard', props: { - on_primary_click: (clicked: Button, event: Gdk.Event): void => { + on_primary_click: (clicked: Button, event: Gdk.Event): void => { openMenu(clicked, event, 'dashboardmenu'); }, + setup: (self: Button): void => { + self.hook(options.bar.scrollSpeed, () => { + const throttledHandler = throttledScrollHandler(options.bar.scrollSpeed.value); + + self.on_secondary_click = (clicked: Button, event: Gdk.Event): void => { + runAsyncCommand(rightClick.value, { clicked, event }); + }; + self.on_middle_click = (clicked: Button, event: Gdk.Event): void => { + runAsyncCommand(middleClick.value, { clicked, event }); + }; + self.on_scroll_up = (clicked: Button, event: Gdk.Event): void => { + throttledHandler(scrollUp.value, { clicked, event }); + }; + self.on_scroll_down = (clicked: Button, event: Gdk.Event): void => { + throttledHandler(scrollDown.value, { clicked, event }); + }; + }); + }, }, }; }; diff --git a/modules/bar/network/index.ts b/modules/bar/network/index.ts index 24c11b83f..1a33e59de 100644 --- a/modules/bar/network/index.ts +++ b/modules/bar/network/index.ts @@ -4,9 +4,18 @@ import options from 'options'; import { openMenu } from '../utils.js'; import { BarBoxChild } from 'lib/types/bar.js'; import Button from 'types/widgets/button.js'; -import { Child } from 'lib/types/widget.js'; +import { Attribute, Child } from 'lib/types/widget.js'; +import { runAsyncCommand, throttledScrollHandler } from 'customModules/utils.js'; -const { label: networkLabel, truncation, truncation_size } = options.bar.network; +const { + label: networkLabel, + truncation, + truncation_size, + rightClick, + middleClick, + scrollDown, + scrollUp, +} = options.bar.network; const Network = (): BarBoxChild => { return { @@ -70,9 +79,27 @@ const Network = (): BarBoxChild => { isVisible: true, boxClass: 'network', props: { - on_primary_click: (clicked: Button, event: Gdk.Event): void => { + on_primary_click: (clicked: Button, event: Gdk.Event): void => { openMenu(clicked, event, 'networkmenu'); }, + setup: (self: Button): void => { + self.hook(options.bar.scrollSpeed, () => { + const throttledHandler = throttledScrollHandler(options.bar.scrollSpeed.value); + + self.on_secondary_click = (clicked: Button, event: Gdk.Event): void => { + runAsyncCommand(rightClick.value, { clicked, event }); + }; + self.on_middle_click = (clicked: Button, event: Gdk.Event): void => { + runAsyncCommand(middleClick.value, { clicked, event }); + }; + self.on_scroll_up = (clicked: Button, event: Gdk.Event): void => { + throttledHandler(scrollUp.value, { clicked, event }); + }; + self.on_scroll_down = (clicked: Button, event: Gdk.Event): void => { + throttledHandler(scrollDown.value, { clicked, event }); + }; + }); + }, }, }; }; diff --git a/modules/bar/notifications/index.ts b/modules/bar/notifications/index.ts index 4a29de41a..c3717b61f 100644 --- a/modules/bar/notifications/index.ts +++ b/modules/bar/notifications/index.ts @@ -4,9 +4,10 @@ import options from 'options'; import { filterNotifications } from 'lib/shared/notifications.js'; import { BarBoxChild } from 'lib/types/bar.js'; import Button from 'types/widgets/button.js'; -import { Child } from 'lib/types/widget.js'; +import { Attribute, Child } from 'lib/types/widget.js'; +import { runAsyncCommand, throttledScrollHandler } from 'customModules/utils.js'; -const { show_total } = options.bar.notifications; +const { show_total, rightClick, middleClick, scrollUp, scrollDown } = options.bar.notifications; const { ignore } = options.notifications; const notifs = await Service.import('notifications'); @@ -58,9 +59,27 @@ export const Notifications = (): BarBoxChild => { isVisible: true, boxClass: 'notifications', props: { - on_primary_click: (clicked: Button, event: Gdk.Event): void => { + on_primary_click: (clicked: Button, event: Gdk.Event): void => { openMenu(clicked, event, 'notificationsmenu'); }, + setup: (self: Button): void => { + self.hook(options.bar.scrollSpeed, () => { + const throttledHandler = throttledScrollHandler(options.bar.scrollSpeed.value); + + self.on_secondary_click = (clicked: Button, event: Gdk.Event): void => { + runAsyncCommand(rightClick.value, { clicked, event }); + }; + self.on_middle_click = (clicked: Button, event: Gdk.Event): void => { + runAsyncCommand(middleClick.value, { clicked, event }); + }; + self.on_scroll_up = (clicked: Button, event: Gdk.Event): void => { + throttledHandler(scrollUp.value, { clicked, event }); + }; + self.on_scroll_down = (clicked: Button, event: Gdk.Event): void => { + throttledHandler(scrollDown.value, { clicked, event }); + }; + }); + }, }, }; }; diff --git a/modules/bar/utils.ts b/modules/bar/utils.ts index 660af79e1..11acac8ad 100644 --- a/modules/bar/utils.ts +++ b/modules/bar/utils.ts @@ -1,5 +1,5 @@ import Gdk from 'gi://Gdk?version=3.0'; -import { Child } from 'lib/types/widget'; +import { Attribute, Child } from 'lib/types/widget'; import Button from 'types/widgets/button'; export const closeAllMenus = (): void => { @@ -20,7 +20,7 @@ export const closeAllMenus = (): void => { }); }; -export const openMenu = (clicked: Button, event: Gdk.Event, window: string): void => { +export const openMenu = (clicked: Button, event: Gdk.Event, window: string): void => { /* * NOTE: We have to make some adjustments so the menu pops up relatively * to the center of the button clicked. We don't want the menu to spawn diff --git a/modules/bar/volume/index.ts b/modules/bar/volume/index.ts index 64e76b863..32fe8dc62 100644 --- a/modules/bar/volume/index.ts +++ b/modules/bar/volume/index.ts @@ -7,7 +7,10 @@ import { VolumeIcons } from 'lib/types/volume.js'; import { BarBoxChild } from 'lib/types/bar.js'; import { Bind } from 'lib/types/variable.js'; import Button from 'types/widgets/button.js'; -import { Child } from 'lib/types/widget.js'; +import { Attribute, Child } from 'lib/types/widget.js'; +import { runAsyncCommand, throttledScrollHandler } from 'customModules/utils.js'; + +const { rightClick, middleClick, scrollUp, scrollDown } = options.bar.volume; const Volume = (): BarBoxChild => { const icons: VolumeIcons = { @@ -75,9 +78,27 @@ const Volume = (): BarBoxChild => { isVisible: true, boxClass: 'volume', props: { - on_primary_click: (clicked: Button, event: Gdk.Event): void => { + onPrimaryClick: (clicked: Button, event: Gdk.Event): void => { openMenu(clicked, event, 'audiomenu'); }, + setup: (self: Button): void => { + self.hook(options.bar.scrollSpeed, () => { + const throttledHandler = throttledScrollHandler(options.bar.scrollSpeed.value); + + self.on_secondary_click = (clicked: Button, event: Gdk.Event): void => { + runAsyncCommand(rightClick.value, { clicked, event }); + }; + self.on_middle_click = (clicked: Button, event: Gdk.Event): void => { + runAsyncCommand(middleClick.value, { clicked, event }); + }; + self.on_scroll_up = (clicked: Button, event: Gdk.Event): void => { + throttledHandler(scrollUp.value, { clicked, event }); + }; + self.on_scroll_down = (clicked: Button, event: Gdk.Event): void => { + throttledHandler(scrollDown.value, { clicked, event }); + }; + }); + }, }, }; }; diff --git a/modules/bar/window_title/index.ts b/modules/bar/window_title/index.ts index d0f1143d8..d5de87082 100644 --- a/modules/bar/window_title/index.ts +++ b/modules/bar/window_title/index.ts @@ -1,9 +1,14 @@ const hyprland = await Service.import('hyprland'); import { BarBoxChild } from 'lib/types/bar'; import options from 'options'; -import { Child } from 'lib/types/widget'; +import { Attribute, Child } from 'lib/types/widget'; import { ActiveClient } from 'types/service/hyprland'; import Label from 'types/widgets/label'; +import { runAsyncCommand, throttledScrollHandler } from 'customModules/utils'; +import Button from 'types/widgets/button'; +import Gdk from 'types/@girs/gdk-3.0/gdk-3.0'; + +const { leftClick, rightClick, middleClick, scrollDown, scrollUp } = options.bar.windowtitle; const filterTitle = (windowtitle: ActiveClient): Record => { const windowTitleMap = [ @@ -207,7 +212,29 @@ const ClientTitle = (): BarBoxChild => { }), isVisible: true, boxClass: 'windowtitle', - props: {}, + props: { + setup: (self: Button): void => { + self.hook(options.bar.scrollSpeed, () => { + const throttledHandler = throttledScrollHandler(options.bar.scrollSpeed.value); + + self.on_primary_click = (clicked: Button, event: Gdk.Event): void => { + runAsyncCommand(leftClick.value, { clicked, event }); + }; + self.on_secondary_click = (clicked: Button, event: Gdk.Event): void => { + runAsyncCommand(rightClick.value, { clicked, event }); + }; + self.on_middle_click = (clicked: Button, event: Gdk.Event): void => { + runAsyncCommand(middleClick.value, { clicked, event }); + }; + self.on_scroll_up = (clicked: Button, event: Gdk.Event): void => { + throttledHandler(scrollUp.value, { clicked, event }); + }; + self.on_scroll_down = (clicked: Button, event: Gdk.Event): void => { + throttledHandler(scrollDown.value, { clicked, event }); + }; + }); + }, + }, }; }; diff --git a/modules/menus/audio/active/SelectedInput.ts b/modules/menus/audio/active/SelectedInput.ts index 2099ae72f..cf47ea108 100644 --- a/modules/menus/audio/active/SelectedInput.ts +++ b/modules/menus/audio/active/SelectedInput.ts @@ -1,8 +1,9 @@ const audio = await Service.import('audio'); -import { BarBoxChild } from 'lib/types/bar.js'; import { getIcon } from '../utils.js'; +import Box from 'types/widgets/box.js'; +import { Attribute, Child } from 'lib/types/widget.js'; -const renderActiveInput = (): BarBoxChild => { +const renderActiveInput = (): Box[] => { return [ Widget.Box({ class_name: 'menu-slider-container input', diff --git a/modules/menus/audio/active/SelectedPlayback.ts b/modules/menus/audio/active/SelectedPlayback.ts index 2ab5887c0..5eedb130a 100644 --- a/modules/menus/audio/active/SelectedPlayback.ts +++ b/modules/menus/audio/active/SelectedPlayback.ts @@ -1,8 +1,9 @@ const audio = await Service.import('audio'); -import { BarBoxChild } from 'lib/types/bar.js'; import { getIcon } from '../utils.js'; +import Box from 'types/widgets/box.js'; +import { Attribute, Child } from 'lib/types/widget.js'; -const renderActivePlayback = (): BarBoxChild => { +const renderActivePlayback = (): Box[] => { return [ Widget.Box({ class_name: 'menu-slider-container playback', diff --git a/modules/menus/audio/active/index.ts b/modules/menus/audio/active/index.ts index fc1c65a03..9768ddb8a 100644 --- a/modules/menus/audio/active/index.ts +++ b/modules/menus/audio/active/index.ts @@ -1,8 +1,9 @@ -import { BarBoxChild } from 'lib/types/bar.js'; import { renderActiveInput } from './SelectedInput.js'; import { renderActivePlayback } from './SelectedPlayback.js'; +import Box from 'types/widgets/box.js'; +import { Attribute, Child } from 'lib/types/widget.js'; -const activeDevices = (): BarBoxChild => { +const activeDevices = (): Box => { return Widget.Box({ class_name: 'menu-section-container volume', vertical: true, diff --git a/options.ts b/options.ts index c711d285e..5b96f2535 100644 --- a/options.ts +++ b/options.ts @@ -781,6 +781,7 @@ const options = mkOptions(OPTIONS, { }, bar: { + scrollSpeed: opt(5), layouts: opt({ '1': { left: ['dashboard', 'workspaces', 'windowtitle'], @@ -800,6 +801,10 @@ const options = mkOptions(OPTIONS, { }), launcher: { icon: opt('󰣇'), + rightClick: opt(''), + middleClick: opt(''), + scrollUp: opt(''), + scrollDown: opt(''), }, windowtitle: { custom_title: opt(true), @@ -809,6 +814,11 @@ const options = mkOptions(OPTIONS, { icon: opt(true), truncation: opt(true), truncation_size: opt(50), + leftClick: opt(''), + rightClick: opt(''), + middleClick: opt(''), + scrollUp: opt(''), + scrollDown: opt(''), }, workspaces: { show_icons: opt(false), @@ -831,17 +841,33 @@ const options = mkOptions(OPTIONS, { }, volume: { label: opt(true), + rightClick: opt(''), + middleClick: opt(''), + scrollUp: opt('pactl set-sink-volume @DEFAULT_SINK@ +5%'), + scrollDown: opt('pactl set-sink-volume @DEFAULT_SINK@ -5%'), }, network: { truncation: opt(true), truncation_size: opt(7), label: opt(true), + rightClick: opt(''), + middleClick: opt(''), + scrollUp: opt(''), + scrollDown: opt(''), }, bluetooth: { label: opt(true), + rightClick: opt(''), + middleClick: opt(''), + scrollUp: opt(''), + scrollDown: opt(''), }, battery: { label: opt(true), + rightClick: opt(''), + middleClick: opt(''), + scrollUp: opt(''), + scrollDown: opt(''), }, systray: { ignore: opt([]), @@ -851,6 +877,10 @@ const options = mkOptions(OPTIONS, { showIcon: opt(true), showTime: opt(true), format: opt('%a %b %d %I:%M:%S %p'), + rightClick: opt(''), + middleClick: opt(''), + scrollUp: opt(''), + scrollDown: opt(''), }, media: { show_artist: opt(false), @@ -858,9 +888,15 @@ const options = mkOptions(OPTIONS, { show_label: opt(true), truncation_size: opt(30), show_active_only: opt(false), + rightClick: opt(''), + middleClick: opt(''), }, notifications: { show_total: opt(false), + rightClick: opt(''), + middleClick: opt(''), + scrollUp: opt(''), + scrollDown: opt(''), }, customModules: { scrollSpeed: opt(5), diff --git a/widget/settings/pages/config/bar/index.ts b/widget/settings/pages/config/bar/index.ts index a213b8869..134c441f6 100644 --- a/widget/settings/pages/config/bar/index.ts +++ b/widget/settings/pages/config/bar/index.ts @@ -118,6 +118,19 @@ export const BarSettings = (): Scrollable => { type: 'string', }), + /* + ****************************** + * Actions * + ****************************** + */ + + Header('Actions'), + Option({ + opt: options.bar.scrollSpeed, + title: 'Scrolling Speed', + subtitle: 'The speed at which the commands assigned to the scroll event will trigger', + type: 'number', + }), /* ****************************** * DASHBOARD * @@ -129,6 +142,26 @@ export const BarSettings = (): Scrollable => { title: 'Dashboard Menu Icon', type: 'string', }), + Option({ + opt: options.bar.launcher.rightClick, + title: 'Right Click', + type: 'string', + }), + Option({ + opt: options.bar.launcher.middleClick, + title: 'Middle Click', + type: 'string', + }), + Option({ + opt: options.bar.launcher.scrollUp, + title: 'Scroll Up', + type: 'string', + }), + Option({ + opt: options.bar.launcher.scrollDown, + title: 'Scroll Down', + type: 'string', + }), /* ****************************** @@ -298,6 +331,31 @@ export const BarSettings = (): Scrollable => { subtitle: 'Spacing between the icon and the label inside the buttons.', type: 'string', }), + Option({ + opt: options.bar.windowtitle.leftClick, + title: 'Left Click', + type: 'string', + }), + Option({ + opt: options.bar.windowtitle.rightClick, + title: 'Right Click', + type: 'string', + }), + Option({ + opt: options.bar.windowtitle.middleClick, + title: 'Middle Click', + type: 'string', + }), + Option({ + opt: options.bar.windowtitle.scrollUp, + title: 'Scroll Up', + type: 'string', + }), + Option({ + opt: options.bar.windowtitle.scrollDown, + title: 'Scroll Down', + type: 'string', + }), /* ****************************** @@ -316,6 +374,26 @@ export const BarSettings = (): Scrollable => { subtitle: 'Spacing between the icon and the label inside the buttons.', type: 'string', }), + Option({ + opt: options.bar.volume.rightClick, + title: 'Right Click', + type: 'string', + }), + Option({ + opt: options.bar.volume.middleClick, + title: 'Middle Click', + type: 'string', + }), + Option({ + opt: options.bar.volume.scrollUp, + title: 'Scroll Up', + type: 'string', + }), + Option({ + opt: options.bar.volume.scrollDown, + title: 'Scroll Down', + type: 'string', + }), /* ****************************** @@ -345,6 +423,26 @@ export const BarSettings = (): Scrollable => { subtitle: 'Spacing between the icon and the label inside the buttons.', type: 'string', }), + Option({ + opt: options.bar.network.rightClick, + title: 'Right Click', + type: 'string', + }), + Option({ + opt: options.bar.network.middleClick, + title: 'Middle Click', + type: 'string', + }), + Option({ + opt: options.bar.network.scrollUp, + title: 'Scroll Up', + type: 'string', + }), + Option({ + opt: options.bar.network.scrollDown, + title: 'Scroll Down', + type: 'string', + }), /* ****************************** @@ -363,6 +461,26 @@ export const BarSettings = (): Scrollable => { subtitle: 'Spacing between the icon and the label inside the buttons.', type: 'string', }), + Option({ + opt: options.bar.bluetooth.rightClick, + title: 'Right Click', + type: 'string', + }), + Option({ + opt: options.bar.bluetooth.middleClick, + title: 'Middle Click', + type: 'string', + }), + Option({ + opt: options.bar.bluetooth.scrollUp, + title: 'Scroll Up', + type: 'string', + }), + Option({ + opt: options.bar.bluetooth.scrollDown, + title: 'Scroll Down', + type: 'string', + }), /* ****************************** @@ -381,6 +499,26 @@ export const BarSettings = (): Scrollable => { subtitle: 'Spacing between the icon and the label inside the buttons.', type: 'string', }), + Option({ + opt: options.bar.battery.rightClick, + title: 'Right Click', + type: 'string', + }), + Option({ + opt: options.bar.battery.middleClick, + title: 'Middle Click', + type: 'string', + }), + Option({ + opt: options.bar.battery.scrollUp, + title: 'Scroll Up', + type: 'string', + }), + Option({ + opt: options.bar.battery.scrollDown, + title: 'Scroll Down', + type: 'string', + }), /* ****************************** @@ -430,6 +568,26 @@ export const BarSettings = (): Scrollable => { subtitle: 'Spacing between the icon and the label inside the buttons.', type: 'string', }), + Option({ + opt: options.bar.clock.rightClick, + title: 'Right Click', + type: 'string', + }), + Option({ + opt: options.bar.clock.middleClick, + title: 'Middle Click', + type: 'string', + }), + Option({ + opt: options.bar.clock.scrollUp, + title: 'Scroll Up', + type: 'string', + }), + Option({ + opt: options.bar.clock.scrollDown, + title: 'Scroll Down', + type: 'string', + }), /* ****************************** @@ -472,6 +630,16 @@ export const BarSettings = (): Scrollable => { subtitle: 'Button will automatically hide if no media is detected.', type: 'boolean', }), + Option({ + opt: options.bar.media.rightClick, + title: 'Right Click', + type: 'string', + }), + Option({ + opt: options.bar.media.middleClick, + title: 'Middle Click', + type: 'string', + }), /* ****************************** @@ -490,6 +658,26 @@ export const BarSettings = (): Scrollable => { subtitle: 'Spacing between the icon and the label inside the buttons.', type: 'string', }), + Option({ + opt: options.bar.notifications.rightClick, + title: 'Right Click', + type: 'string', + }), + Option({ + opt: options.bar.notifications.middleClick, + title: 'Middle Click', + type: 'string', + }), + Option({ + opt: options.bar.notifications.scrollUp, + title: 'Scroll Up', + type: 'string', + }), + Option({ + opt: options.bar.notifications.scrollDown, + title: 'Scroll Down', + type: 'string', + }), ], }), });