refactor(ags lint): customise eslint and apply to config
This commit is contained in:
parent
a645fc5857
commit
71108d1852
59 changed files with 1690 additions and 936 deletions
|
@ -8,33 +8,133 @@
|
||||||
"ecmaVersion": "latest",
|
"ecmaVersion": "latest",
|
||||||
"sourceType": "module"
|
"sourceType": "module"
|
||||||
},
|
},
|
||||||
|
"plugins": ["@stylistic"],
|
||||||
"rules": {
|
"rules": {
|
||||||
"arrow-parens": ["error", "as-needed"],
|
"array-callback-return": ["error", {
|
||||||
"comma-dangle": ["error", "always-multiline"],
|
"allowImplicit": true,
|
||||||
"comma-spacing": ["error", { "before": false, "after": true }],
|
"checkForEach": true
|
||||||
"comma-style": ["error", "last"],
|
}],
|
||||||
"curly": ["error", "multi-or-nest", "consistent"],
|
"no-constructor-return": ["error"],
|
||||||
"dot-location": ["error", "property"],
|
"no-unreachable-loop": ["error", { "ignore": [
|
||||||
"eol-last": 0,
|
"ForInStatement", "ForOfStatement"
|
||||||
"indent": ["error", 4, { "SwitchCase": 1 }],
|
]}],
|
||||||
"keyword-spacing": ["error", { "before": true }],
|
"no-use-before-define": ["error", {
|
||||||
"lines-between-class-members": ["error", "always", { "exceptAfterSingleLine": true }],
|
"functions": false
|
||||||
"padded-blocks": ["error", "never", { "allowSingleLineBlocks": false }],
|
}],
|
||||||
"prefer-const": "error",
|
|
||||||
"quotes": ["error", "single", { "avoidEscape": true }],
|
|
||||||
"semi": ["error", "always"],
|
"block-scoped-var": ["error"],
|
||||||
"nonblock-statement-body-position": ["error", "below"],
|
"capitalized-comments": ["warn", "always", {
|
||||||
"no-trailing-spaces": ["error"],
|
"ignoreConsecutiveComments": true
|
||||||
"no-dupe-class-members": 0,
|
}],
|
||||||
"array-bracket-spacing": ["error", "never"],
|
"class-methods-use-this": ["error"],
|
||||||
"key-spacing": ["error", { "beforeColon": false, "afterColon": true }],
|
"curly": ["warn"],
|
||||||
"object-curly-spacing": ["error", "always"],
|
"default-case-last": ["warn"],
|
||||||
"no-useless-escape": ["off"]
|
"default-param-last": ["error"],
|
||||||
|
"dot-notation": ["warn", { "allowPattern": ".*-|_.*" }],
|
||||||
|
"eqeqeq": ["error", "smart"],
|
||||||
|
"func-names": ["warn", "never"],
|
||||||
|
"func-style": ["warn", "expression"],
|
||||||
|
"logical-assignment-operators": ["warn", "always"],
|
||||||
|
"no-array-constructor": ["error"],
|
||||||
|
"no-else-return": ["error"],
|
||||||
|
"no-empty-function": ["warn"],
|
||||||
|
"no-empty-static-block": ["warn"],
|
||||||
|
"no-extend-native": ["error"],
|
||||||
|
"no-extra-bind": ["warn"],
|
||||||
|
"no-implicit-coercion": ["warn"],
|
||||||
|
"no-iterator": ["error"],
|
||||||
|
"no-labels": ["error"],
|
||||||
|
"no-lone-blocks": ["error"],
|
||||||
|
"no-lonely-if": ["error"],
|
||||||
|
"no-loop-func": ["error"],
|
||||||
|
"no-magic-numbers": ["error", {
|
||||||
|
"ignore": [-1, 0.1, 0, 1, 2, 3, 10, 33, 66, 100, 255, 360, 450, 1000],
|
||||||
|
"ignoreDefaultValues": true
|
||||||
|
}],
|
||||||
|
"no-multi-assign": ["error"],
|
||||||
|
"no-negated-condition": ["warn"],
|
||||||
|
"no-new": ["error"],
|
||||||
|
"no-new-func": ["error"],
|
||||||
|
"no-new-wrappers": ["error"],
|
||||||
|
"no-object-constructor": ["error"],
|
||||||
|
"no-proto": ["error"],
|
||||||
|
"no-return-assign": ["error"],
|
||||||
|
"no-sequences": ["error"],
|
||||||
|
"no-shadow": ["error", { "builtinGlobals": true }],
|
||||||
|
"no-undef-init": ["warn"],
|
||||||
|
"no-undefined": ["error"],
|
||||||
|
"no-useless-constructor": ["warn"],
|
||||||
|
"no-useless-escape": ["off"],
|
||||||
|
"no-useless-return": ["error"],
|
||||||
|
"no-var": ["error"],
|
||||||
|
"no-void": ["error"],
|
||||||
|
"no-with": ["error"],
|
||||||
|
"object-shorthand": ["error", "always"],
|
||||||
|
"one-var": ["error", "never"],
|
||||||
|
"operator-assignment": ["warn", "always"],
|
||||||
|
"prefer-arrow-callback": ["error"],
|
||||||
|
"prefer-const": ["error"],
|
||||||
|
"prefer-object-has-own": ["error"],
|
||||||
|
"prefer-regex-literals": ["error"],
|
||||||
|
"prefer-template": ["warn"],
|
||||||
|
|
||||||
|
|
||||||
|
"@stylistic/array-bracket-newline": ["warn", "consistent"],
|
||||||
|
"@stylistic/array-bracket-spacing": ["warn", "never"],
|
||||||
|
"@stylistic/arrow-parens": ["warn", "always"],
|
||||||
|
"@stylistic/brace-style": ["warn", "stroustrup"],
|
||||||
|
"@stylistic/comma-dangle": ["warn", "always-multiline"],
|
||||||
|
"@stylistic/comma-spacing": ["warn", { "before": false, "after": true }],
|
||||||
|
"@stylistic/comma-style": ["error", "last"],
|
||||||
|
"@stylistic/dot-location": ["error", "property"],
|
||||||
|
"@stylistic/function-call-argument-newline": ["warn", "consistent"],
|
||||||
|
"@stylistic/function-paren-newline": ["warn", "consistent"],
|
||||||
|
"@stylistic/indent": ["warn", 4, {
|
||||||
|
"SwitchCase": 1,
|
||||||
|
"ignoreComments": true
|
||||||
|
}],
|
||||||
|
"@stylistic/key-spacing": ["warn", { "beforeColon": false, "afterColon": true }],
|
||||||
|
"@stylistic/keyword-spacing": ["warn", { "before": true }],
|
||||||
|
"@stylistic/linebreak-style": ["error", "unix"],
|
||||||
|
"@stylistic/lines-between-class-members": ["warn", "always", { "exceptAfterSingleLine": true }],
|
||||||
|
"@stylistic/max-len": ["warn", {
|
||||||
|
"code": 80,
|
||||||
|
"ignoreComments": true,
|
||||||
|
"ignoreTrailingComments": true,
|
||||||
|
"ignoreUrls": true
|
||||||
|
}],
|
||||||
|
"@stylistic/multiline-ternary": ["warn", "always-multiline"],
|
||||||
|
"@stylistic/new-parens": ["error"],
|
||||||
|
"@stylistic/no-mixed-operators": ["warn"],
|
||||||
|
"@stylistic/no-mixed-spaces-and-tabs": ["error"],
|
||||||
|
"@stylistic/no-multi-spaces": ["error"],
|
||||||
|
"@stylistic/no-tabs": ["error"],
|
||||||
|
"@stylistic/no-trailing-spaces": ["error"],
|
||||||
|
"@stylistic/no-whitespace-before-property": ["warn"],
|
||||||
|
"@stylistic/nonblock-statement-body-position": ["error", "below"],
|
||||||
|
"@stylistic/object-curly-newline": ["warn", { "consistent": true }],
|
||||||
|
"@stylistic/object-curly-spacing": ["warn", "always"],
|
||||||
|
"@stylistic/operator-linebreak": ["warn", "after"],
|
||||||
|
"@stylistic/padded-blocks": ["error", "never"],
|
||||||
|
"@stylistic/padding-line-between-statements": ["warn",
|
||||||
|
{ "blankLine": "always", "prev": "*", "next": "return" },
|
||||||
|
{ "blankLine": "always", "prev": ["const", "let", "var"], "next": "*"},
|
||||||
|
{ "blankLine": "any", "prev": ["const", "let", "var"], "next": ["const", "let", "var"]},
|
||||||
|
{ "blankLine": "always", "prev": ["case", "default"], "next": "*" }
|
||||||
|
],
|
||||||
|
"@stylistic/quote-props": ["error", "consistent-as-needed"],
|
||||||
|
"@stylistic/quotes": ["error", "single", { "avoidEscape": true }],
|
||||||
|
"@stylistic/semi": ["error", "always"],
|
||||||
|
"@stylistic/semi-spacing": ["warn"],
|
||||||
|
"@stylistic/space-before-blocks": ["warn"],
|
||||||
|
"@stylistic/space-before-function-paren": ["warn", "never"],
|
||||||
|
"@stylistic/space-infix-ops": ["warn"],
|
||||||
|
"@stylistic/spaced-comment": ["warn", "always"],
|
||||||
|
"@stylistic/switch-colon-spacing": ["warn"],
|
||||||
|
"@stylistic/wrap-regex": ["warn"]
|
||||||
},
|
},
|
||||||
"globals": {
|
"globals": {
|
||||||
"Tablet": "readonly",
|
|
||||||
"Pointers": "readonly",
|
|
||||||
"Brightness": "readonly",
|
|
||||||
"ARGV": "readonly",
|
"ARGV": "readonly",
|
||||||
"imports": "readonly",
|
"imports": "readonly",
|
||||||
"print": "readonly",
|
"print": "readonly",
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
|
|
||||||
import App from 'resource:///com/github/Aylur/ags/app.js';
|
import App from 'resource:///com/github/Aylur/ags/app.js';
|
||||||
import Widget from 'resource:///com/github/Aylur/ags/widget.js';
|
import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
|
||||||
|
|
||||||
|
import { Box, Button, Icon, Label } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
import { lookUpIcon } from 'resource:///com/github/Aylur/ags/utils.js';
|
import { lookUpIcon } from 'resource:///com/github/Aylur/ags/utils.js';
|
||||||
|
|
||||||
import Separator from '../misc/separator.js';
|
import Separator from '../misc/separator.js';
|
||||||
|
|
||||||
|
|
||||||
export default app => {
|
export default (app) => {
|
||||||
const title = Widget.Label({
|
const title = Label({
|
||||||
class_name: 'title',
|
class_name: 'title',
|
||||||
label: app.name,
|
label: app.name,
|
||||||
xalign: 0,
|
xalign: 0,
|
||||||
|
@ -15,7 +16,7 @@ export default app => {
|
||||||
truncate: 'end',
|
truncate: 'end',
|
||||||
});
|
});
|
||||||
|
|
||||||
const description = Widget.Label({
|
const description = Label({
|
||||||
class_name: 'description',
|
class_name: 'description',
|
||||||
label: app.description || '',
|
label: app.description || '',
|
||||||
wrap: true,
|
wrap: true,
|
||||||
|
@ -24,28 +25,42 @@ export default app => {
|
||||||
vpack: 'center',
|
vpack: 'center',
|
||||||
});
|
});
|
||||||
|
|
||||||
const icon = Widget.Icon({
|
const icon = Icon({
|
||||||
icon: lookUpIcon(app.icon_name) ? app.icon_name :
|
icon: lookUpIcon(app.icon_name) ?
|
||||||
app.app.get_string('Icon') !== 'nix-snowflake' ? app.app.get_string('Icon') : '',
|
app.icon_name :
|
||||||
|
app.app.get_string('Icon') === 'nix-snowflake' ?
|
||||||
|
'' :
|
||||||
|
app.app.get_string('Icon'),
|
||||||
size: 42,
|
size: 42,
|
||||||
});
|
});
|
||||||
|
|
||||||
const textBox = Widget.Box({
|
const textBox = Box({
|
||||||
vertical: true,
|
vertical: true,
|
||||||
vpack: 'center',
|
vpack: 'center',
|
||||||
children: [title, description],
|
children: [title, description],
|
||||||
});
|
});
|
||||||
|
|
||||||
return Widget.Button({
|
const ENTRY_SPACING = 16;
|
||||||
|
|
||||||
|
return Button({
|
||||||
class_name: 'app',
|
class_name: 'app',
|
||||||
setup: self => self.app = app,
|
|
||||||
|
setup: (self) => {
|
||||||
|
self.app = app;
|
||||||
|
},
|
||||||
|
|
||||||
on_clicked: () => {
|
on_clicked: () => {
|
||||||
App.closeWindow('applauncher');
|
App.closeWindow('applauncher');
|
||||||
Hyprland.sendMessage(`dispatch exec sh -c ${app.executable}`);
|
Hyprland.sendMessage(`dispatch exec sh -c ${app.executable}`);
|
||||||
++app.frequency;
|
++app.frequency;
|
||||||
},
|
},
|
||||||
child: Widget.Box({
|
|
||||||
children: [icon, Separator(16), textBox],
|
child: Box({
|
||||||
|
children: [
|
||||||
|
icon,
|
||||||
|
Separator(ENTRY_SPACING),
|
||||||
|
textBox,
|
||||||
|
],
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,17 +10,20 @@ import AppItem from './app-item.js';
|
||||||
|
|
||||||
|
|
||||||
const Applauncher = ({ window_name = 'applauncher' } = {}) => {
|
const Applauncher = ({ window_name = 'applauncher' } = {}) => {
|
||||||
|
const ICON_SEPARATION = 4;
|
||||||
|
|
||||||
const children = () => [
|
const children = () => [
|
||||||
...Applications.query('').flatMap(app => {
|
...Applications.query('').flatMap((app) => {
|
||||||
const item = AppItem(app);
|
const item = AppItem(app);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
Separator(4, {
|
Separator(ICON_SEPARATION, {
|
||||||
binds: [['visible', item, 'visible']],
|
binds: [['visible', item, 'visible']],
|
||||||
}),
|
}),
|
||||||
item,
|
item,
|
||||||
];
|
];
|
||||||
}),
|
}),
|
||||||
Separator(4),
|
Separator(ICON_SEPARATION),
|
||||||
];
|
];
|
||||||
|
|
||||||
const list = Box({
|
const list = Box({
|
||||||
|
@ -28,43 +31,46 @@ const Applauncher = ({ window_name = 'applauncher' } = {}) => {
|
||||||
children: children(),
|
children: children(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const entry = Entry({
|
const placeholder = Label({
|
||||||
hexpand: true,
|
label: " Couldn't find a match",
|
||||||
placeholder_text: 'Search',
|
className: 'placeholder',
|
||||||
|
});
|
||||||
|
|
||||||
// set some text so on-change works the first time
|
const entry = Entry({
|
||||||
|
// Set some text so on-change works the first time
|
||||||
text: '-',
|
text: '-',
|
||||||
|
hexpand: true,
|
||||||
|
|
||||||
on_accept: ({ text }) => {
|
on_accept: ({ text }) => {
|
||||||
const list = Applications.query(text || '');
|
const appList = Applications.query(text || '');
|
||||||
if (list[0]) {
|
|
||||||
|
if (appList[0]) {
|
||||||
App.toggleWindow(window_name);
|
App.toggleWindow(window_name);
|
||||||
Hyprland.sendMessage(`dispatch exec sh -c ${list[0]}`);
|
Hyprland.sendMessage(`dispatch exec sh -c ${appList[0]}`);
|
||||||
++list[0].frequency;
|
++appList[0].frequency;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
on_change: ({ text }) => {
|
on_change: ({ text }) => {
|
||||||
let visibleApps = 0;
|
let visibleApps = 0;
|
||||||
list.children.map(item => {
|
|
||||||
|
list.children.forEach((item) => {
|
||||||
if (item.app) {
|
if (item.app) {
|
||||||
item.visible = item.app.match(text);
|
item.visible = item.app.match(text);
|
||||||
|
|
||||||
if (item.app.match(text))
|
if (item.app.match(text)) {
|
||||||
++visibleApps;
|
++visibleApps;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
placeholder.visible = visibleApps <= 0;
|
placeholder.visible = visibleApps <= 0;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const placeholder = Label({
|
|
||||||
label: " Couldn't find a match",
|
|
||||||
className: 'placeholder',
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
return Box({
|
return Box({
|
||||||
className: 'applauncher',
|
className: 'applauncher',
|
||||||
vertical: true,
|
vertical: true,
|
||||||
|
|
||||||
children: [
|
children: [
|
||||||
Box({
|
Box({
|
||||||
className: 'header',
|
className: 'header',
|
||||||
|
@ -82,15 +88,20 @@ const Applauncher = ({ window_name = 'applauncher' } = {}) => {
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
|
||||||
connections: [[App, (_, name, visible) => {
|
connections: [[App, (_, name, visible) => {
|
||||||
if (name !== window_name)
|
if (name !== window_name) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
entry.text = '';
|
entry.text = '';
|
||||||
if (visible)
|
|
||||||
|
if (visible) {
|
||||||
entry.grab_focus();
|
entry.grab_focus();
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
list.children = children();
|
list.children = children();
|
||||||
|
}
|
||||||
}]],
|
}]],
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import Audio from 'resource:///com/github/Aylur/ags/service/audio.js';
|
import Audio from 'resource:///com/github/Aylur/ags/service/audio.js';
|
||||||
|
|
||||||
import { Label, Box, Icon } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Label, Box, Icon } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
import { execAsync } from 'resource:///com/github/Aylur/ags/utils.js';
|
import { execAsync } from 'resource:///com/github/Aylur/ags/utils.js';
|
||||||
|
|
||||||
|
@ -7,27 +8,32 @@ import Separator from '../../misc/separator.js';
|
||||||
import EventBox from '../../misc/cursorbox.js';
|
import EventBox from '../../misc/cursorbox.js';
|
||||||
|
|
||||||
|
|
||||||
const SpeakerIndicator = props => Icon({
|
const SpeakerIndicator = (props) => Icon({
|
||||||
...props,
|
...props,
|
||||||
binds: [['icon', SpeakerIcon, 'value']],
|
binds: [['icon', SpeakerIcon, 'value']],
|
||||||
});
|
});
|
||||||
|
|
||||||
const SpeakerPercentLabel = props => Label({
|
const SpeakerPercentLabel = (props) => Label({
|
||||||
...props,
|
...props,
|
||||||
connections: [[Audio, label => {
|
connections: [[Audio, (label) => {
|
||||||
if (Audio.speaker)
|
if (Audio.speaker) {
|
||||||
label.label = Math.round(Audio.speaker.volume * 100) + '%';
|
label.label = `${Math.round(Audio.speaker.volume * 100)}%`;
|
||||||
|
}
|
||||||
}, 'speaker-changed']],
|
}, 'speaker-changed']],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const SPACING = 5;
|
||||||
|
|
||||||
export default () => EventBox({
|
export default () => EventBox({
|
||||||
onPrimaryClickRelease: () => execAsync(['pavucontrol']).catch(print),
|
|
||||||
className: 'toggle-off',
|
className: 'toggle-off',
|
||||||
|
|
||||||
|
onPrimaryClickRelease: () => execAsync(['pavucontrol']).catch(print),
|
||||||
|
|
||||||
child: Box({
|
child: Box({
|
||||||
className: 'audio',
|
className: 'audio',
|
||||||
children: [
|
children: [
|
||||||
SpeakerIndicator(),
|
SpeakerIndicator(),
|
||||||
Separator(5),
|
Separator(SPACING),
|
||||||
SpeakerPercentLabel(),
|
SpeakerPercentLabel(),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -1,30 +1,41 @@
|
||||||
import Battery from 'resource:///com/github/Aylur/ags/service/battery.js';
|
import Battery from 'resource:///com/github/Aylur/ags/service/battery.js';
|
||||||
|
|
||||||
import { Label, Icon, Box } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Label, Icon, Box } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
|
|
||||||
import Separator from '../../misc/separator.js';
|
import Separator from '../../misc/separator.js';
|
||||||
|
|
||||||
|
const LOW_BATT = 20;
|
||||||
|
|
||||||
|
|
||||||
const Indicator = () => Icon({
|
const Indicator = () => Icon({
|
||||||
className: 'battery-indicator',
|
className: 'battery-indicator',
|
||||||
|
|
||||||
binds: [['icon', Battery, 'icon-name']],
|
binds: [['icon', Battery, 'icon-name']],
|
||||||
connections: [[Battery, self => {
|
|
||||||
|
connections: [[Battery, (self) => {
|
||||||
self.toggleClassName('charging', Battery.charging);
|
self.toggleClassName('charging', Battery.charging);
|
||||||
self.toggleClassName('charged', Battery.charged);
|
self.toggleClassName('charged', Battery.charged);
|
||||||
self.toggleClassName('low', Battery.percent < 20);
|
self.toggleClassName('low', Battery.percent < LOW_BATT);
|
||||||
}]],
|
}]],
|
||||||
});
|
});
|
||||||
|
|
||||||
const LevelLabel = props => Label({
|
const LevelLabel = (props) => Label({
|
||||||
...props,
|
...props,
|
||||||
className: 'label',
|
className: 'label',
|
||||||
connections: [[Battery, self => self.label = `${Battery.percent}%`]],
|
|
||||||
|
connections: [[Battery, (self) => {
|
||||||
|
self.label = `${Battery.percent}%`;
|
||||||
|
}]],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const SPACING = 5;
|
||||||
|
|
||||||
export default () => Box({
|
export default () => Box({
|
||||||
className: 'toggle-off battery',
|
className: 'toggle-off battery',
|
||||||
|
|
||||||
children: [
|
children: [
|
||||||
Indicator(),
|
Indicator(),
|
||||||
Separator(5),
|
Separator(SPACING),
|
||||||
LevelLabel(),
|
LevelLabel(),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,22 +1,30 @@
|
||||||
import { ProgressBar, Overlay, Box } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { ProgressBar, Overlay, Box } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
|
|
||||||
|
import Brightness from '../../../services/brightness.js';
|
||||||
import Separator from '../../misc/separator.js';
|
import Separator from '../../misc/separator.js';
|
||||||
import Heart from './heart.js';
|
import Heart from './heart.js';
|
||||||
|
|
||||||
|
const SPACING = 25;
|
||||||
|
const BAR_CUTOFF = 0.33;
|
||||||
|
|
||||||
|
|
||||||
export default () => Overlay({
|
export default () => Overlay({
|
||||||
tooltipText: 'Brightness',
|
tooltipText: 'Brightness',
|
||||||
|
|
||||||
child: ProgressBar({
|
child: ProgressBar({
|
||||||
className: 'toggle-off brightness',
|
className: 'toggle-off brightness',
|
||||||
connections: [[Brightness, self => {
|
connections: [[Brightness, (self) => {
|
||||||
self.value = Brightness.screen > 0.33 ? Brightness.screen : 0.33;
|
self.value = Brightness.screen > BAR_CUTOFF ?
|
||||||
|
Brightness.screen :
|
||||||
|
BAR_CUTOFF;
|
||||||
}, 'screen']],
|
}, 'screen']],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
overlays: [
|
overlays: [
|
||||||
Box({
|
Box({
|
||||||
css: 'color: #CBA6F7;',
|
css: 'color: #CBA6F7;',
|
||||||
children: [
|
children: [
|
||||||
Separator(25),
|
Separator(SPACING),
|
||||||
Heart(),
|
Heart(),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import App from 'resource:///com/github/Aylur/ags/app.js';
|
import App from 'resource:///com/github/Aylur/ags/app.js';
|
||||||
import { Box, Label } from 'resource:///com/github/Aylur/ags/widget.js';
|
|
||||||
|
import { Label } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
|
|
||||||
import GLib from 'gi://GLib';
|
import GLib from 'gi://GLib';
|
||||||
const { DateTime } = GLib;
|
const { DateTime } = GLib;
|
||||||
|
@ -10,29 +11,33 @@ import EventBox from '../../misc/cursorbox.js';
|
||||||
const ClockModule = ({
|
const ClockModule = ({
|
||||||
interval = 1000,
|
interval = 1000,
|
||||||
...props
|
...props
|
||||||
}) => Label({
|
} = {}) => {
|
||||||
|
return Label({
|
||||||
...props,
|
...props,
|
||||||
className: 'clock',
|
className: 'clock',
|
||||||
connections: [
|
|
||||||
[interval, self => {
|
connections: [[interval, (self) => {
|
||||||
var time = DateTime.new_now_local();
|
const time = DateTime.new_now_local();
|
||||||
|
|
||||||
self.label = time.format('%a. ') +
|
self.label = time.format('%a. ') +
|
||||||
time.get_day_of_month() +
|
time.get_day_of_month() +
|
||||||
time.format(' %b. %H:%M');
|
time.format(' %b. %H:%M');
|
||||||
}],
|
}]],
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export default () => EventBox({
|
export default () => EventBox({
|
||||||
className: 'toggle-off',
|
className: 'toggle-off',
|
||||||
|
|
||||||
onPrimaryClickRelease: () => App.toggleWindow('calendar'),
|
onPrimaryClickRelease: () => App.toggleWindow('calendar'),
|
||||||
|
|
||||||
connections: [
|
connections: [
|
||||||
[App, (self, windowName, visible) => {
|
[App, (self, windowName, visible) => {
|
||||||
if (windowName == 'calendar')
|
if (windowName === 'calendar') {
|
||||||
self.toggleClassName('toggle-on', visible);
|
self.toggleClassName('toggle-on', visible);
|
||||||
|
}
|
||||||
}],
|
}],
|
||||||
],
|
],
|
||||||
child: Box({
|
|
||||||
child: ClockModule({}),
|
child: ClockModule(),
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
|
import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
|
||||||
|
|
||||||
import { Label } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Label } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -17,10 +17,13 @@ export default () => EventBox({
|
||||||
|
|
||||||
child: Label({
|
child: Label({
|
||||||
label: '',
|
label: '',
|
||||||
setup: self => {
|
|
||||||
|
setup: (self) => {
|
||||||
subprocess(
|
subprocess(
|
||||||
['bash', '-c', 'tail -f /home/matt/.config/.heart'],
|
['bash', '-c', 'tail -f /home/matt/.config/.heart'],
|
||||||
output => self.label = ' ' + output,
|
(output) => {
|
||||||
|
self.label = ` ${output}`;
|
||||||
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
|
import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
|
||||||
|
|
||||||
import { Box, Icon, Label } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Box, Icon, Label } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
|
|
||||||
const DEFAULT_KB = 'at-translated-set-2-keyboard';
|
const DEFAULT_KB = 'at-translated-set-2-keyboard';
|
||||||
|
@ -7,17 +8,29 @@ const DEFAULT_KB = 'at-translated-set-2-keyboard';
|
||||||
export default () => Box({
|
export default () => Box({
|
||||||
className: 'toggle-off',
|
className: 'toggle-off',
|
||||||
css: 'padding: 0 10px;',
|
css: 'padding: 0 10px;',
|
||||||
|
|
||||||
children: [
|
children: [
|
||||||
Icon({
|
Icon({
|
||||||
icon: 'input-keyboard-symbolic',
|
icon: 'input-keyboard-symbolic',
|
||||||
css: 'margin-right: 4px;',
|
css: 'margin-right: 4px;',
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Label({
|
Label({
|
||||||
connections: [[Hyprland, (self, _n, layout) => {
|
connections: [[Hyprland, (self, _n, layout) => {
|
||||||
if (!layout) {
|
if (layout) {
|
||||||
Hyprland.sendMessage('j/devices').then(obj => {
|
if (layout === 'error') {
|
||||||
const kb = JSON.parse(obj)['keyboards']
|
return;
|
||||||
.find(val => val.name === DEFAULT_KB);
|
}
|
||||||
|
|
||||||
|
const shortName = layout.match(/\(([A-Za-z]+)\)/);
|
||||||
|
|
||||||
|
self.label = shortName ? shortName[1] : layout;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// At launch, kb layout is undefined
|
||||||
|
Hyprland.sendMessage('j/devices').then((obj) => {
|
||||||
|
const kb = JSON.parse(obj).keyboards
|
||||||
|
.find((val) => val.name === DEFAULT_KB);
|
||||||
|
|
||||||
layout = kb['active_keymap'];
|
layout = kb['active_keymap'];
|
||||||
|
|
||||||
|
@ -26,14 +39,6 @@ export default () => Box({
|
||||||
self.label = shortName ? shortName[1] : layout;
|
self.label = shortName ? shortName[1] : layout;
|
||||||
}).catch(print);
|
}).catch(print);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
if (layout === 'error')
|
|
||||||
return;
|
|
||||||
|
|
||||||
const shortName = layout.match(/\(([A-Za-z]+)\)/);
|
|
||||||
|
|
||||||
self.label = shortName ? shortName[1] : layout;
|
|
||||||
}
|
|
||||||
}, 'keyboard-layout']],
|
}, 'keyboard-layout']],
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
|
|
@ -1,44 +1,52 @@
|
||||||
import App from 'resource:///com/github/Aylur/ags/app.js';
|
import App from 'resource:///com/github/Aylur/ags/app.js';
|
||||||
import Notifications from 'resource:///com/github/Aylur/ags/service/notifications.js';
|
import Notifications from 'resource:///com/github/Aylur/ags/service/notifications.js';
|
||||||
|
|
||||||
import { Box, Icon, Label } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Box, Icon, Label } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
|
|
||||||
import Separator from '../../misc/separator.js';
|
import Separator from '../../misc/separator.js';
|
||||||
import EventBox from '../../misc/cursorbox.js';
|
import EventBox from '../../misc/cursorbox.js';
|
||||||
|
|
||||||
|
const L_PADDING = 28;
|
||||||
|
const R_PADDING = 8;
|
||||||
|
|
||||||
|
|
||||||
export default () => EventBox({
|
export default () => EventBox({
|
||||||
className: 'toggle-off',
|
className: 'toggle-off',
|
||||||
|
|
||||||
onPrimaryClickRelease: () => App.toggleWindow('notification-center'),
|
onPrimaryClickRelease: () => App.toggleWindow('notification-center'),
|
||||||
|
|
||||||
connections: [[App, (self, windowName, visible) => {
|
connections: [[App, (self, windowName, visible) => {
|
||||||
if (windowName == 'notification-center')
|
if (windowName === 'notification-center') {
|
||||||
self.toggleClassName('toggle-on', visible);
|
self.toggleClassName('toggle-on', visible);
|
||||||
|
}
|
||||||
}]],
|
}]],
|
||||||
|
|
||||||
child: Box({
|
child: Box({
|
||||||
className: 'notif-panel',
|
className: 'notif-panel',
|
||||||
vertical: false,
|
vertical: false,
|
||||||
|
|
||||||
children: [
|
children: [
|
||||||
Separator(28),
|
Separator(L_PADDING),
|
||||||
|
|
||||||
Icon({
|
Icon({
|
||||||
connections: [[Notifications, self => {
|
connections: [[Notifications, (self) => {
|
||||||
if (Notifications.dnd) {
|
if (Notifications.dnd) {
|
||||||
self.icon = 'notification-disabled-symbolic';
|
self.icon = 'notification-disabled-symbolic';
|
||||||
}
|
}
|
||||||
else {
|
else if (Notifications.notifications.length > 0) {
|
||||||
if (Notifications.notifications.length > 0)
|
|
||||||
self.icon = 'notification-new-symbolic';
|
self.icon = 'notification-new-symbolic';
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
self.icon = 'notification-symbolic';
|
self.icon = 'notification-symbolic';
|
||||||
}
|
}
|
||||||
}]],
|
}]],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Separator(8),
|
Separator(R_PADDING),
|
||||||
|
|
||||||
Label({
|
Label({
|
||||||
binds: [
|
binds: [['label', Notifications, 'notifications',
|
||||||
['label', Notifications, 'notifications', n => String(n.length)],
|
(n) => String(n.length)]],
|
||||||
],
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
],
|
],
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
import { Box, Label } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Box, Label } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
|
|
||||||
|
import Tablet from '../../../services/tablet.js';
|
||||||
import EventBox from '../../misc/cursorbox.js';
|
import EventBox from '../../misc/cursorbox.js';
|
||||||
|
|
||||||
|
|
||||||
export default () => EventBox({
|
export default () => EventBox({
|
||||||
className: 'toggle-off',
|
className: 'toggle-off',
|
||||||
|
|
||||||
onPrimaryClickRelease: () => Tablet.toggleOsk(),
|
onPrimaryClickRelease: () => Tablet.toggleOsk(),
|
||||||
|
|
||||||
connections: [[Tablet, self => {
|
connections: [[Tablet, (self) => {
|
||||||
self.toggleClassName('toggle-on', Tablet.oskState);
|
self.toggleClassName('toggle-on', Tablet.oskState);
|
||||||
}, 'osk-toggled']],
|
}, 'osk-toggled']],
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import App from 'resource:///com/github/Aylur/ags/app.js';
|
import App from 'resource:///com/github/Aylur/ags/app.js';
|
||||||
|
|
||||||
import { Box, Label } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Box, Label } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
|
|
||||||
import EventBox from '../../misc/cursorbox.js';
|
import EventBox from '../../misc/cursorbox.js';
|
||||||
|
@ -6,11 +7,15 @@ import EventBox from '../../misc/cursorbox.js';
|
||||||
|
|
||||||
export default () => EventBox({
|
export default () => EventBox({
|
||||||
className: 'toggle-off',
|
className: 'toggle-off',
|
||||||
|
|
||||||
onPrimaryClickRelease: () => App.toggleWindow('quick-settings'),
|
onPrimaryClickRelease: () => App.toggleWindow('quick-settings'),
|
||||||
|
|
||||||
connections: [[App, (self, windowName, visible) => {
|
connections: [[App, (self, windowName, visible) => {
|
||||||
if (windowName == 'quick-settings')
|
if (windowName === 'quick-settings') {
|
||||||
self.toggleClassName('toggle-on', visible);
|
self.toggleClassName('toggle-on', visible);
|
||||||
|
}
|
||||||
}]],
|
}]],
|
||||||
|
|
||||||
child: Box({
|
child: Box({
|
||||||
className: 'quick-settings-toggle',
|
className: 'quick-settings-toggle',
|
||||||
vertical: false,
|
vertical: false,
|
||||||
|
|
|
@ -1,17 +1,24 @@
|
||||||
import SystemTray from 'resource:///com/github/Aylur/ags/service/systemtray.js';
|
import SystemTray from 'resource:///com/github/Aylur/ags/service/systemtray.js';
|
||||||
|
|
||||||
import { timeout } from 'resource:///com/github/Aylur/ags/utils.js';
|
import { timeout } from 'resource:///com/github/Aylur/ags/utils.js';
|
||||||
import { Box, Icon, MenuItem, MenuBar, Revealer } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Box, Icon, MenuItem, MenuBar, Revealer } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
|
|
||||||
import Separator from '../../misc/separator.js';
|
import Separator from '../../misc/separator.js';
|
||||||
|
|
||||||
|
const REVEAL_DURATION = 500;
|
||||||
|
const SPACING = 12;
|
||||||
|
|
||||||
const SysTrayItem = item => {
|
|
||||||
if (item.id === 'spotify-client')
|
const SysTrayItem = (item) => {
|
||||||
|
if (item.id === 'spotify-client') {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
return MenuItem({
|
return MenuItem({
|
||||||
child: Revealer({
|
child: Revealer({
|
||||||
transition: 'slide_right',
|
transition: 'slide_right',
|
||||||
|
transitionDuration: REVEAL_DURATION,
|
||||||
|
|
||||||
child: Icon({
|
child: Icon({
|
||||||
size: 24,
|
size: 24,
|
||||||
binds: [['icon', item, 'icon']],
|
binds: [['icon', item, 'icon']],
|
||||||
|
@ -23,18 +30,22 @@ const SysTrayItem = item => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const SysTray = () => MenuBar({
|
const SysTray = () => MenuBar({
|
||||||
setup: self => {
|
setup: (self) => {
|
||||||
self.items = new Map();
|
self.items = new Map();
|
||||||
|
|
||||||
self.onAdded = id => {
|
self.onAdded = (id) => {
|
||||||
const item = SystemTray.getItem(id);
|
const item = SystemTray.getItem(id);
|
||||||
if (self.items.has(id) || !item)
|
|
||||||
|
if (self.items.has(id) || !item) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const w = SysTrayItem(item);
|
const w = SysTrayItem(item);
|
||||||
|
|
||||||
// Early return if item is in blocklist
|
// Early return if item is in blocklist
|
||||||
if (!w)
|
if (!w) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
self.items.set(id, w);
|
self.items.set(id, w);
|
||||||
self.add(w);
|
self.add(w);
|
||||||
|
@ -42,12 +53,13 @@ const SysTray = () => MenuBar({
|
||||||
w.child.revealChild = true;
|
w.child.revealChild = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
self.onRemoved = id => {
|
self.onRemoved = (id) => {
|
||||||
if (!self.items.has(id))
|
if (!self.items.has(id)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
self.items.get(id).child.revealChild = false;
|
self.items.get(id).child.revealChild = false;
|
||||||
timeout(400, () => {
|
timeout(REVEAL_DURATION, () => {
|
||||||
self.items.get(id).destroy();
|
self.items.get(id).destroy();
|
||||||
self.items.delete(id);
|
self.items.delete(id);
|
||||||
});
|
});
|
||||||
|
@ -59,20 +71,25 @@ const SysTray = () => MenuBar({
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
export default () => Revealer({
|
export default () => {
|
||||||
|
const systray = SysTray();
|
||||||
|
|
||||||
|
return Revealer({
|
||||||
transition: 'slide_right',
|
transition: 'slide_right',
|
||||||
connections: [[SystemTray, rev => {
|
|
||||||
rev.revealChild = rev.child.children[0].get_children().length > 0;
|
connections: [[SystemTray, (rev) => {
|
||||||
|
rev.revealChild = systray.get_children().length > 0;
|
||||||
}]],
|
}]],
|
||||||
|
|
||||||
child: Box({
|
child: Box({
|
||||||
children: [
|
children: [
|
||||||
Box({
|
Box({
|
||||||
className: 'sys-tray',
|
className: 'sys-tray',
|
||||||
children: [
|
children: [systray],
|
||||||
SysTray(),
|
|
||||||
],
|
|
||||||
}),
|
}),
|
||||||
Separator(12),
|
|
||||||
|
Separator(SPACING),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
import { Box, Label } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Box, Label } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
|
|
||||||
|
import Tablet from '../../../services/tablet.js';
|
||||||
import EventBox from '../../misc/cursorbox.js';
|
import EventBox from '../../misc/cursorbox.js';
|
||||||
|
|
||||||
|
|
||||||
export default () => EventBox({
|
export default () => EventBox({
|
||||||
className: 'toggle-off',
|
className: 'toggle-off',
|
||||||
|
|
||||||
onPrimaryClickRelease: () => Tablet.toggleMode(),
|
onPrimaryClickRelease: () => Tablet.toggleMode(),
|
||||||
|
|
||||||
connections: [[Tablet, self => {
|
connections: [[Tablet, (self) => {
|
||||||
self.toggleClassName('toggle-on', Tablet.tabletMode);
|
self.toggleClassName('toggle-on', Tablet.tabletMode);
|
||||||
}, 'mode-toggled']],
|
}, 'mode-toggled']],
|
||||||
|
|
||||||
|
|
|
@ -1,24 +1,33 @@
|
||||||
import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
|
import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
|
||||||
|
|
||||||
import { timeout } from 'resource:///com/github/Aylur/ags/utils.js';
|
import { timeout } from 'resource:///com/github/Aylur/ags/utils.js';
|
||||||
import { Box, Overlay, Revealer } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Box, Overlay, Revealer } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
|
|
||||||
import EventBox from '../../misc/cursorbox.js';
|
import EventBox from '../../misc/cursorbox.js';
|
||||||
|
|
||||||
|
const URGENT_DURATION = 1000;
|
||||||
|
|
||||||
const Workspace = ({ i } = {}) =>
|
|
||||||
Revealer({
|
const Workspace = ({ i } = {}) => {
|
||||||
|
return Revealer({
|
||||||
transition: 'slide_right',
|
transition: 'slide_right',
|
||||||
properties: [['id', i]],
|
properties: [['id', i]],
|
||||||
|
|
||||||
child: EventBox({
|
child: EventBox({
|
||||||
tooltipText: `${i}`,
|
tooltipText: `${i}`,
|
||||||
onPrimaryClickRelease: () => Hyprland.sendMessage(`dispatch workspace ${i}`),
|
|
||||||
|
onPrimaryClickRelease: () => {
|
||||||
|
Hyprland.sendMessage(`dispatch workspace ${i}`);
|
||||||
|
},
|
||||||
|
|
||||||
child: Box({
|
child: Box({
|
||||||
vpack: 'center',
|
vpack: 'center',
|
||||||
className: 'button',
|
className: 'button',
|
||||||
setup: self => {
|
|
||||||
self.update = addr => {
|
setup: (self) => {
|
||||||
|
self.update = (addr) => {
|
||||||
const occupied = Hyprland.getWorkspace(i)?.windows > 0;
|
const occupied = Hyprland.getWorkspace(i)?.windows > 0;
|
||||||
|
|
||||||
self.toggleClassName('occupied', occupied);
|
self.toggleClassName('occupied', occupied);
|
||||||
self.toggleClassName('empty', !occupied);
|
self.toggleClassName('empty', !occupied);
|
||||||
|
|
||||||
|
@ -27,36 +36,47 @@ const Workspace = ({ i } = {}) =>
|
||||||
self.toggleClassName('urgent', true);
|
self.toggleClassName('urgent', true);
|
||||||
|
|
||||||
// Only show for a sec when urgent is current workspace
|
// Only show for a sec when urgent is current workspace
|
||||||
if (Hyprland.active.workspace.id === i)
|
if (Hyprland.active.workspace.id === i) {
|
||||||
timeout(1000, () => self.toggleClassName('urgent', false));
|
timeout(URGENT_DURATION, () => {
|
||||||
|
self.toggleClassName('urgent', false);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
connections: [
|
connections: [
|
||||||
[Hyprland, self => self.update()],
|
[Hyprland, (self) => self.update()],
|
||||||
|
|
||||||
// Deal with urgent windows
|
// Deal with urgent windows
|
||||||
[Hyprland, (self, addr) => self.update(addr), 'urgent-window'],
|
[Hyprland, (self, a) => self.update(a), 'urgent-window'],
|
||||||
[Hyprland.active.workspace, self => {
|
[Hyprland.active.workspace, (self) => {
|
||||||
if (Hyprland.active.workspace.id === i)
|
if (Hyprland.active.workspace.id === i) {
|
||||||
self.toggleClassName('urgent', false);
|
self.toggleClassName('urgent', false);
|
||||||
|
}
|
||||||
}],
|
}],
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const updateHighlight = () => {
|
const L_PADDING = 16;
|
||||||
|
const WS_WIDTH = 30;
|
||||||
|
|
||||||
|
const updateHighlight = (self) => {
|
||||||
const currentId = Hyprland.active.workspace.id;
|
const currentId = Hyprland.active.workspace.id;
|
||||||
const indicators = highlight.get_parent().get_children()[0].child.children;
|
const indicators = self.get_parent().get_children()[0].child.children;
|
||||||
const currentIndex = indicators.findIndex(w => w._id == currentId);
|
const currentIndex = indicators.findIndex((w) => w._id === currentId);
|
||||||
|
|
||||||
if (currentIndex < 0)
|
if (currentIndex < 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
highlight.setCss(`margin-left: ${16 + currentIndex * 30}px`);
|
self.setCss(`margin-left: ${L_PADDING + (currentIndex * WS_WIDTH)}px`);
|
||||||
};
|
};
|
||||||
|
|
||||||
const highlight = Box({
|
const highlight = Box({
|
||||||
vpack: 'center',
|
vpack: 'center',
|
||||||
hpack: 'start',
|
hpack: 'start',
|
||||||
|
@ -70,21 +90,28 @@ export default () => {
|
||||||
child: EventBox({
|
child: EventBox({
|
||||||
child: Box({
|
child: Box({
|
||||||
className: 'workspaces',
|
className: 'workspaces',
|
||||||
|
|
||||||
properties: [
|
properties: [
|
||||||
['workspaces'],
|
['workspaces'],
|
||||||
|
|
||||||
['refresh', self => {
|
['refresh', (self) => {
|
||||||
self.children.forEach(rev => rev.reveal_child = false);
|
self.children.forEach((rev) => {
|
||||||
self._workspaces.forEach(ws => {
|
rev.reveal_child = false;
|
||||||
|
});
|
||||||
|
self._workspaces.forEach((ws) => {
|
||||||
ws.revealChild = true;
|
ws.revealChild = true;
|
||||||
});
|
});
|
||||||
}],
|
}],
|
||||||
|
|
||||||
['updateWorkspaces', self => {
|
['updateWorkspaces', (self) => {
|
||||||
Hyprland.workspaces.forEach(ws => {
|
Hyprland.workspaces.forEach((ws) => {
|
||||||
const currentWs = self.children.find(ch => ch._id == ws.id);
|
const currentWs = self.children.find((ch) => {
|
||||||
if (!currentWs && ws.id > 0)
|
return ch._id === ws.id;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!currentWs && ws.id > 0) {
|
||||||
self.add(Workspace({ i: ws.id }));
|
self.add(Workspace({ i: ws.id }));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
self.show_all();
|
self.show_all();
|
||||||
|
|
||||||
|
@ -94,16 +121,21 @@ export default () => {
|
||||||
});
|
});
|
||||||
}],
|
}],
|
||||||
],
|
],
|
||||||
connections: [[Hyprland, self => {
|
|
||||||
self._workspaces = self.children.filter(ch => {
|
connections: [[Hyprland, (self) => {
|
||||||
return Hyprland.workspaces.find(ws => ws.id == ch._id);
|
self._workspaces = self.children.filter((ch) => {
|
||||||
|
return Hyprland.workspaces.find((ws) => {
|
||||||
|
return ws.id === ch._id;
|
||||||
|
});
|
||||||
}).sort((a, b) => a._id - b._id);
|
}).sort((a, b) => a._id - b._id);
|
||||||
|
|
||||||
self._updateWorkspaces(self);
|
self._updateWorkspaces(self);
|
||||||
self._refresh(self);
|
self._refresh(self);
|
||||||
|
|
||||||
// Make sure the highlight doesn't go too far
|
// Make sure the highlight doesn't go too far
|
||||||
timeout(10, updateHighlight);
|
const TEMP_TIMEOUT = 10;
|
||||||
|
|
||||||
|
timeout(TEMP_TIMEOUT, () => updateHighlight(highlight));
|
||||||
}]],
|
}]],
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -4,23 +4,25 @@ import Variable from 'resource:///com/github/Aylur/ags/variable.js';
|
||||||
import { Box, EventBox, Revealer, Window } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Box, EventBox, Revealer, Window } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
|
|
||||||
|
|
||||||
const BarCloser = variable => Window({
|
const BarCloser = (variable) => Window({
|
||||||
name: 'bar-closer',
|
name: 'bar-closer',
|
||||||
visible: false,
|
visible: false,
|
||||||
anchor: ['top', 'bottom', 'left', 'right'],
|
anchor: ['top', 'bottom', 'left', 'right'],
|
||||||
layer: 'overlay',
|
layer: 'overlay',
|
||||||
|
|
||||||
child: EventBox({
|
child: EventBox({
|
||||||
onHover: self => {
|
onHover: (self) => {
|
||||||
variable.value = false;
|
variable.value = false;
|
||||||
self.get_parent().visible = false;
|
self.get_parent().visible = false;
|
||||||
},
|
},
|
||||||
|
|
||||||
child: Box({
|
child: Box({
|
||||||
css: 'padding: 1px',
|
css: 'padding: 1px',
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default props => {
|
export default (props) => {
|
||||||
const Revealed = Variable(true);
|
const Revealed = Variable(true);
|
||||||
const barCloser = BarCloser(Revealed);
|
const barCloser = BarCloser(Revealed);
|
||||||
|
|
||||||
|
@ -28,28 +30,39 @@ export default props => {
|
||||||
css: 'min-height: 1px',
|
css: 'min-height: 1px',
|
||||||
hexpand: true,
|
hexpand: true,
|
||||||
vertical: true,
|
vertical: true,
|
||||||
|
|
||||||
connections: [
|
connections: [
|
||||||
[Hyprland.active, () => {
|
[Hyprland.active, () => {
|
||||||
const workspace = Hyprland.getWorkspace(Hyprland.active.workspace.id);
|
const workspace = Hyprland.getWorkspace(
|
||||||
|
Hyprland.active.workspace.id,
|
||||||
|
);
|
||||||
|
|
||||||
Revealed.value = !workspace?.hasfullscreen;
|
Revealed.value = !workspace?.hasfullscreen;
|
||||||
}],
|
}],
|
||||||
[Hyprland, (_, fullscreen) => Revealed.value = !fullscreen, 'fullscreen'],
|
|
||||||
|
[Hyprland, (_, fullscreen) => {
|
||||||
|
Revealed.value = !fullscreen;
|
||||||
|
}, 'fullscreen'],
|
||||||
],
|
],
|
||||||
|
|
||||||
children: [
|
children: [
|
||||||
Revealer({
|
Revealer({
|
||||||
|
...props,
|
||||||
transition: 'slide_down',
|
transition: 'slide_down',
|
||||||
revealChild: true,
|
revealChild: true,
|
||||||
|
|
||||||
binds: [['revealChild', Revealed, 'value']],
|
binds: [['revealChild', Revealed, 'value']],
|
||||||
...props,
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Revealer({
|
Revealer({
|
||||||
binds: [['revealChild', Revealed, 'value', v => !v]],
|
binds: [['revealChild', Revealed, 'value', (v) => !v]],
|
||||||
|
|
||||||
child: EventBox({
|
child: EventBox({
|
||||||
onHover: () => {
|
onHover: () => {
|
||||||
barCloser.visible = true;
|
barCloser.visible = true;
|
||||||
Revealed.value = true;
|
Revealed.value = true;
|
||||||
},
|
},
|
||||||
|
|
||||||
child: Box({
|
child: Box({
|
||||||
css: 'min-height: 5px;',
|
css: 'min-height: 5px;',
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -1,21 +1,24 @@
|
||||||
import { Window, CenterBox, Box } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Window, CenterBox, Box } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
|
|
||||||
import Separator from '../misc/separator.js';
|
import Separator from '../misc/separator.js';
|
||||||
import CurrentWindow from './buttons/current-window.js';
|
|
||||||
import Workspaces from './buttons/workspaces.js';
|
import Audio from './buttons/audio.js';
|
||||||
import OskToggle from './buttons/osk-toggle.js';
|
|
||||||
import TabletToggle from './buttons/tablet-toggle.js';
|
|
||||||
import QsToggle from './buttons/quick-settings.js';
|
|
||||||
import NotifButton from './buttons/notif-button.js';
|
|
||||||
import Clock from './buttons/clock.js';
|
|
||||||
import SysTray from './buttons/systray.js';
|
|
||||||
import Battery from './buttons/battery.js';
|
import Battery from './buttons/battery.js';
|
||||||
import Brightness from './buttons/brightness.js';
|
import Brightness from './buttons/brightness.js';
|
||||||
import Audio from './buttons/audio.js';
|
import Clock from './buttons/clock.js';
|
||||||
|
import CurrentWindow from './buttons/current-window.js';
|
||||||
import KeyboardLayout from './buttons/keyboard-layout.js';
|
import KeyboardLayout from './buttons/keyboard-layout.js';
|
||||||
|
import NotifButton from './buttons/notif-button.js';
|
||||||
|
import OskToggle from './buttons/osk-toggle.js';
|
||||||
|
import QsToggle from './buttons/quick-settings.js';
|
||||||
|
import SysTray from './buttons/systray.js';
|
||||||
|
import TabletToggle from './buttons/tablet-toggle.js';
|
||||||
|
import Workspaces from './buttons/workspaces.js';
|
||||||
|
|
||||||
import BarReveal from './fullscreen.js';
|
import BarReveal from './fullscreen.js';
|
||||||
|
|
||||||
|
const SPACING = 12;
|
||||||
|
|
||||||
|
|
||||||
export default () => Window({
|
export default () => Window({
|
||||||
name: 'bar',
|
name: 'bar',
|
||||||
|
@ -33,21 +36,21 @@ export default () => Window({
|
||||||
|
|
||||||
OskToggle(),
|
OskToggle(),
|
||||||
|
|
||||||
Separator(12),
|
Separator(SPACING),
|
||||||
|
|
||||||
TabletToggle(),
|
TabletToggle(),
|
||||||
|
|
||||||
Separator(12),
|
Separator(SPACING),
|
||||||
|
|
||||||
SysTray(),
|
SysTray(),
|
||||||
|
|
||||||
Audio(),
|
Audio(),
|
||||||
|
|
||||||
Separator(12),
|
Separator(SPACING),
|
||||||
|
|
||||||
Brightness(),
|
Brightness(),
|
||||||
|
|
||||||
Separator(12),
|
Separator(SPACING),
|
||||||
|
|
||||||
Workspaces(),
|
Workspaces(),
|
||||||
|
|
||||||
|
@ -56,11 +59,11 @@ export default () => Window({
|
||||||
|
|
||||||
centerWidget: Box({
|
centerWidget: Box({
|
||||||
children: [
|
children: [
|
||||||
Separator(12),
|
Separator(SPACING),
|
||||||
|
|
||||||
CurrentWindow(),
|
CurrentWindow(),
|
||||||
|
|
||||||
Separator(12),
|
Separator(SPACING),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
@ -69,19 +72,19 @@ export default () => Window({
|
||||||
children: [
|
children: [
|
||||||
Battery(),
|
Battery(),
|
||||||
|
|
||||||
Separator(12),
|
Separator(SPACING),
|
||||||
|
|
||||||
KeyboardLayout(),
|
KeyboardLayout(),
|
||||||
|
|
||||||
Separator(12),
|
Separator(SPACING),
|
||||||
|
|
||||||
Clock(),
|
Clock(),
|
||||||
|
|
||||||
Separator(12),
|
Separator(SPACING),
|
||||||
|
|
||||||
NotifButton(),
|
NotifButton(),
|
||||||
|
|
||||||
Separator(12),
|
Separator(SPACING),
|
||||||
|
|
||||||
QsToggle(),
|
QsToggle(),
|
||||||
],
|
],
|
||||||
|
|
|
@ -11,6 +11,7 @@ const TopLeft = () => Window({
|
||||||
visible: true,
|
visible: true,
|
||||||
child: RoundedCorner('topleft'),
|
child: RoundedCorner('topleft'),
|
||||||
});
|
});
|
||||||
|
|
||||||
const TopRight = () => Window({
|
const TopRight = () => Window({
|
||||||
name: 'cornertr',
|
name: 'cornertr',
|
||||||
layer: 'overlay',
|
layer: 'overlay',
|
||||||
|
@ -19,6 +20,7 @@ const TopRight = () => Window({
|
||||||
visible: true,
|
visible: true,
|
||||||
child: RoundedCorner('topright'),
|
child: RoundedCorner('topright'),
|
||||||
});
|
});
|
||||||
|
|
||||||
const BottomLeft = () => Window({
|
const BottomLeft = () => Window({
|
||||||
name: 'cornerbl',
|
name: 'cornerbl',
|
||||||
layer: 'overlay',
|
layer: 'overlay',
|
||||||
|
@ -27,6 +29,7 @@ const BottomLeft = () => Window({
|
||||||
visible: true,
|
visible: true,
|
||||||
child: RoundedCorner('bottomleft'),
|
child: RoundedCorner('bottomleft'),
|
||||||
});
|
});
|
||||||
|
|
||||||
const BottomRight = () => Window({
|
const BottomRight = () => Window({
|
||||||
name: 'cornerbr',
|
name: 'cornerbr',
|
||||||
layer: 'overlay',
|
layer: 'overlay',
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { Box, DrawingArea } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Box, DrawingArea } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
|
|
||||||
import Gtk from 'gi://Gtk';
|
import Gtk from 'gi://Gtk';
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
|
|
||||||
|
@ -19,25 +20,27 @@ export default (
|
||||||
css: `
|
css: `
|
||||||
border-radius: 18px;
|
border-radius: 18px;
|
||||||
border-width: 0.068rem;
|
border-width: 0.068rem;
|
||||||
` + css,
|
${css}
|
||||||
setup: widget => {
|
`,
|
||||||
const r = widget.get_style_context()
|
setup: (widget) => {
|
||||||
|
let r = widget.get_style_context()
|
||||||
.get_property('border-radius', Gtk.StateFlags.NORMAL);
|
.get_property('border-radius', Gtk.StateFlags.NORMAL);
|
||||||
|
|
||||||
widget.set_size_request(r, r);
|
widget.set_size_request(r, r);
|
||||||
widget.connect('draw', Lang.bind(widget, (widget, cr) => {
|
widget.connect('draw', Lang.bind(widget, (_, cr) => {
|
||||||
const c = widget.get_style_context()
|
const c = widget.get_style_context()
|
||||||
.get_property('background-color', Gtk.StateFlags.NORMAL);
|
.get_property('background-color', Gtk.StateFlags.NORMAL);
|
||||||
|
|
||||||
const r = widget.get_style_context()
|
r = widget.get_style_context()
|
||||||
.get_property('border-radius', Gtk.StateFlags.NORMAL);
|
.get_property('border-radius', Gtk.StateFlags.NORMAL);
|
||||||
|
|
||||||
const borderColor = widget.get_style_context()
|
const borderColor = widget.get_style_context()
|
||||||
.get_property('color', Gtk.StateFlags.NORMAL);
|
.get_property('color', Gtk.StateFlags.NORMAL);
|
||||||
|
|
||||||
// ur going to write border-width: something anyway
|
// Ur going to write border-width: something anyway
|
||||||
const borderWidth = widget.get_style_context()
|
const borderWidth = widget.get_style_context()
|
||||||
.get_border(Gtk.StateFlags.NORMAL).left;
|
.get_border(Gtk.StateFlags.NORMAL).left;
|
||||||
|
|
||||||
widget.set_size_request(r, r);
|
widget.set_size_request(r, r);
|
||||||
|
|
||||||
switch (place) {
|
switch (place) {
|
||||||
|
|
|
@ -25,7 +25,7 @@ const Time = () => Box({
|
||||||
Label({
|
Label({
|
||||||
className: 'content',
|
className: 'content',
|
||||||
label: 'hour',
|
label: 'hour',
|
||||||
connections: [[1000, self => {
|
connections: [[1000, (self) => {
|
||||||
self.label = DateTime.new_now_local().format('%H');
|
self.label = DateTime.new_now_local().format('%H');
|
||||||
}]],
|
}]],
|
||||||
}),
|
}),
|
||||||
|
@ -35,7 +35,7 @@ const Time = () => Box({
|
||||||
Label({
|
Label({
|
||||||
className: 'content',
|
className: 'content',
|
||||||
label: 'minute',
|
label: 'minute',
|
||||||
connections: [[1000, self => {
|
connections: [[1000, (self) => {
|
||||||
self.label = DateTime.new_now_local().format('%M');
|
self.label = DateTime.new_now_local().format('%M');
|
||||||
}]],
|
}]],
|
||||||
}),
|
}),
|
||||||
|
@ -49,8 +49,9 @@ const Time = () => Box({
|
||||||
child: Label({
|
child: Label({
|
||||||
css: 'font-size: 20px',
|
css: 'font-size: 20px',
|
||||||
label: 'complete date',
|
label: 'complete date',
|
||||||
connections: [[1000, self => {
|
connections: [[1000, (self) => {
|
||||||
var time = DateTime.new_now_local();
|
const time = DateTime.new_now_local();
|
||||||
|
|
||||||
self.label = time.format('%A, %B ') +
|
self.label = time.format('%A, %B ') +
|
||||||
time.get_day_of_month() +
|
time.get_day_of_month() +
|
||||||
time.format(', %Y');
|
time.format(', %Y');
|
||||||
|
@ -70,9 +71,12 @@ const CalendarWidget = () => Box({
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const TOP_MARGIN = 6;
|
||||||
|
const RIGHT_MARGIN = 182;
|
||||||
|
|
||||||
export default () => PopupWindow({
|
export default () => PopupWindow({
|
||||||
anchor: ['top', 'right'],
|
anchor: ['top', 'right'],
|
||||||
margins: [6, 182, 0, 0],
|
margins: [TOP_MARGIN, RIGHT_MARGIN, 0, 0],
|
||||||
name: 'calendar',
|
name: 'calendar',
|
||||||
child: Box({
|
child: Box({
|
||||||
className: 'date',
|
className: 'date',
|
||||||
|
|
|
@ -5,7 +5,9 @@ import Gtk from 'gi://Gtk';
|
||||||
|
|
||||||
const MAX_OFFSET = 200;
|
const MAX_OFFSET = 200;
|
||||||
const OFFSCREEN = 500;
|
const OFFSCREEN = 500;
|
||||||
const TRANSITION = 'transition: margin 0.5s ease, opacity 3s ease;';
|
const ANIM_DURATION = 500;
|
||||||
|
const TRANSITION = `transition: margin ${ANIM_DURATION}ms ease,
|
||||||
|
opacity 3s ease;`;
|
||||||
|
|
||||||
|
|
||||||
export default ({
|
export default ({
|
||||||
|
@ -25,16 +27,18 @@ export default ({
|
||||||
|
|
||||||
// Have empty PlayerBox to define the size of the widget
|
// Have empty PlayerBox to define the size of the widget
|
||||||
child: Box({ className: 'player' }),
|
child: Box({ className: 'player' }),
|
||||||
|
|
||||||
connections: [
|
connections: [
|
||||||
...connections,
|
...connections,
|
||||||
|
|
||||||
[gesture, overlay => {
|
[gesture, (overlay) => {
|
||||||
// Don't allow gesture when only one player
|
// Don't allow gesture when only one player
|
||||||
if (overlay.list().length <= 1)
|
if (overlay.list().length <= 1) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
overlay._dragging = true;
|
overlay._dragging = true;
|
||||||
var offset = gesture.get_offset()[1];
|
let offset = gesture.get_offset()[1];
|
||||||
|
|
||||||
const playerBox = overlay.list().at(-1);
|
const playerBox = overlay.list().at(-1);
|
||||||
|
|
||||||
|
@ -58,10 +62,11 @@ export default ({
|
||||||
}
|
}
|
||||||
}, 'drag-update'],
|
}, 'drag-update'],
|
||||||
|
|
||||||
[gesture, overlay => {
|
[gesture, (overlay) => {
|
||||||
// Don't allow gesture when only one player
|
// Don't allow gesture when only one player
|
||||||
if (overlay.list().length <= 1)
|
if (overlay.list().length <= 1) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
overlay._dragging = false;
|
overlay._dragging = false;
|
||||||
const offset = gesture.get_offset()[1];
|
const offset = gesture.get_offset()[1];
|
||||||
|
@ -92,7 +97,7 @@ export default ({
|
||||||
opacity: 0; ${playerBox._bgStyle}`);
|
opacity: 0; ${playerBox._bgStyle}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
timeout(500, () => {
|
timeout(ANIM_DURATION, () => {
|
||||||
// Put the player in the back after anim
|
// Put the player in the back after anim
|
||||||
overlay.reorder_overlay(playerBox, 0);
|
overlay.reorder_overlay(playerBox, 0);
|
||||||
// Recenter player
|
// Recenter player
|
||||||
|
@ -108,7 +113,9 @@ export default ({
|
||||||
}, 'drag-end'],
|
}, 'drag-end'],
|
||||||
],
|
],
|
||||||
}));
|
}));
|
||||||
widget.child.list = () => widget.child.get_children().filter(ch => ch._bgStyle !== undefined);
|
|
||||||
|
widget.child.list = () => widget.child.get_children()
|
||||||
|
.filter((ch) => ch._bgStyle);
|
||||||
|
|
||||||
return widget;
|
return widget;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import Mpris from 'resource:///com/github/Aylur/ags/service/mpris.js';
|
import Mpris from 'resource:///com/github/Aylur/ags/service/mpris.js';
|
||||||
|
|
||||||
import { Button, Icon, Label, Stack, Slider, CenterBox, Box } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Button, Icon, Label, Stack, Slider, CenterBox, Box } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
import { execAsync, lookUpIcon, readFileAsync } from 'resource:///com/github/Aylur/ags/utils.js';
|
import { execAsync, lookUpIcon, readFileAsync } from 'resource:///com/github/Aylur/ags/utils.js';
|
||||||
|
|
||||||
|
@ -29,16 +30,18 @@ const icons = {
|
||||||
export const CoverArt = (player, props) => CenterBox({
|
export const CoverArt = (player, props) => CenterBox({
|
||||||
...props,
|
...props,
|
||||||
vertical: true,
|
vertical: true,
|
||||||
|
|
||||||
properties: [['bgStyle', '']],
|
properties: [['bgStyle', '']],
|
||||||
setup: self => {
|
|
||||||
|
setup: (self) => {
|
||||||
// Give temp cover art
|
// Give temp cover art
|
||||||
readFileAsync(player.coverPath).catch(() => {
|
readFileAsync(player.coverPath).catch(() => {
|
||||||
if (!player.colors.value && !player.trackCoverUrl) {
|
if (!player.colors.value && !player.trackCoverUrl) {
|
||||||
player.colors.value = {
|
player.colors.value = {
|
||||||
'imageAccent': '#6b4fa2',
|
imageAccent: '#6b4fa2',
|
||||||
'buttonAccent': '#ecdcff',
|
buttonAccent: '#ecdcff',
|
||||||
'buttonText': '#25005a',
|
buttonText: '#25005a',
|
||||||
'hoverAccent': '#d4baff',
|
hoverAccent: '#d4baff',
|
||||||
};
|
};
|
||||||
|
|
||||||
self._bgStyle = `
|
self._bgStyle = `
|
||||||
|
@ -53,12 +56,14 @@ export const CoverArt = (player, props) => CenterBox({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
connections: [[player, self => {
|
|
||||||
|
connections: [[player, (self) => {
|
||||||
execAsync(['bash', '-c', `[[ -f "${player.coverPath}" ]] &&
|
execAsync(['bash', '-c', `[[ -f "${player.coverPath}" ]] &&
|
||||||
coloryou "${player.coverPath}" | grep -v Warning`])
|
coloryou "${player.coverPath}" | grep -v Warning`])
|
||||||
.then(out => {
|
.then((out) => {
|
||||||
if (!Mpris.players.find(p => player === p))
|
if (!Mpris.players.find((p) => player === p)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
player.colors.value = JSON.parse(out);
|
player.colors.value = JSON.parse(out);
|
||||||
|
|
||||||
|
@ -71,11 +76,13 @@ export const CoverArt = (player, props) => CenterBox({
|
||||||
background-position: center;
|
background-position: center;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
if (!self.get_parent()._dragging)
|
if (!self.get_parent()._dragging) {
|
||||||
self.setCss(self._bgStyle);
|
self.setCss(self._bgStyle);
|
||||||
}).catch(err => {
|
}
|
||||||
if (err !== '')
|
}).catch((err) => {
|
||||||
|
if (err !== '') {
|
||||||
print(err);
|
print(err);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}]],
|
}]],
|
||||||
});
|
});
|
||||||
|
@ -87,6 +94,7 @@ export const TitleLabel = (player, props) => Label({
|
||||||
truncate: 'end',
|
truncate: 'end',
|
||||||
justification: 'left',
|
justification: 'left',
|
||||||
className: 'title',
|
className: 'title',
|
||||||
|
|
||||||
binds: [['label', player, 'track-title']],
|
binds: [['label', player, 'track-title']],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -97,7 +105,8 @@ export const ArtistLabel = (player, props) => Label({
|
||||||
truncate: 'end',
|
truncate: 'end',
|
||||||
justification: 'left',
|
justification: 'left',
|
||||||
className: 'artist',
|
className: 'artist',
|
||||||
binds: [['label', player, 'track-artists', a => a.join(', ') || '']],
|
|
||||||
|
binds: [['label', player, 'track-artists', (a) => a.join(', ') || '']],
|
||||||
});
|
});
|
||||||
|
|
||||||
export const PlayerIcon = (player, { symbolic = true, ...props } = {}) => {
|
export const PlayerIcon = (player, { symbolic = true, ...props } = {}) => {
|
||||||
|
@ -107,28 +116,34 @@ export const PlayerIcon = (player, { symbolic = true, ...props } = {}) => {
|
||||||
className: 'player-icon',
|
className: 'player-icon',
|
||||||
size: 32,
|
size: 32,
|
||||||
tooltipText: player.identity || '',
|
tooltipText: player.identity || '',
|
||||||
connections: [[player, self => {
|
|
||||||
|
connections: [[player, (self) => {
|
||||||
const name = `${player.entry}${symbolic ? '-symbolic' : ''}`;
|
const name = `${player.entry}${symbolic ? '-symbolic' : ''}`;
|
||||||
lookUpIcon(name) ? self.icon = name
|
|
||||||
: self.icon = icons.mpris.fallback;
|
lookUpIcon(name) ?
|
||||||
|
self.icon = name :
|
||||||
|
self.icon = icons.mpris.fallback;
|
||||||
}]],
|
}]],
|
||||||
});
|
});
|
||||||
|
|
||||||
// Multiple player indicators
|
// Multiple player indicators
|
||||||
return Box({
|
return Box({
|
||||||
properties: [['overlay']],
|
properties: [['overlay']],
|
||||||
connections: [[Mpris, self => {
|
connections: [[Mpris, (self) => {
|
||||||
if (!self._overlay)
|
if (!self._overlay) {
|
||||||
self._overlay = self.get_parent().get_parent().get_parent();
|
self._overlay = self.get_parent().get_parent().get_parent();
|
||||||
|
}
|
||||||
|
|
||||||
const overlays = self._overlay.list();
|
const overlays = self._overlay.list();
|
||||||
|
|
||||||
const player = overlays.find(overlay => {
|
const playerWidget = overlays.find((overlay) => {
|
||||||
return overlay === self.get_parent().get_parent();
|
return overlay === self.get_parent().get_parent();
|
||||||
});
|
});
|
||||||
|
|
||||||
const index = overlays.indexOf(player);
|
const index = overlays.indexOf(playerWidget);
|
||||||
|
|
||||||
const children = [];
|
const children = [];
|
||||||
|
|
||||||
for (let i = 0; i < overlays.length; ++i) {
|
for (let i = 0; i < overlays.length; ++i) {
|
||||||
if (i === index) {
|
if (i === index) {
|
||||||
children.push(Separator(2));
|
children.push(Separator(2));
|
||||||
|
@ -152,22 +167,27 @@ export const PositionSlider = (player, props) => Slider({
|
||||||
vpack: 'center',
|
vpack: 'center',
|
||||||
hexpand: true,
|
hexpand: true,
|
||||||
drawValue: false,
|
drawValue: false,
|
||||||
|
|
||||||
onChange: ({ value }) => {
|
onChange: ({ value }) => {
|
||||||
player.position = player.length * value;
|
player.position = player.length * value;
|
||||||
},
|
},
|
||||||
properties: [['update', slider => {
|
|
||||||
|
properties: [['update', (slider) => {
|
||||||
if (!slider.dragging) {
|
if (!slider.dragging) {
|
||||||
slider.visible = player.length > 0;
|
slider.visible = player.length > 0;
|
||||||
if (player.length > 0)
|
if (player.length > 0) {
|
||||||
slider.value = player.position / player.length;
|
slider.value = player.position / player.length;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}]],
|
}]],
|
||||||
|
|
||||||
connections: [
|
connections: [
|
||||||
[player, s => s._update(s), 'position'],
|
[1000, (s) => s._update(s)],
|
||||||
[1000, s => s._update(s)],
|
[player, (s) => s._update(s), 'position'],
|
||||||
[player.colors, s => {
|
[player.colors, (s) => {
|
||||||
const c = player.colors.value;
|
|
||||||
if (player.colors.value) {
|
if (player.colors.value) {
|
||||||
|
const c = player.colors.value;
|
||||||
|
|
||||||
s.setCss(`
|
s.setCss(`
|
||||||
highlight { background-color: ${c.buttonAccent}; }
|
highlight { background-color: ${c.buttonAccent}; }
|
||||||
slider { background-color: ${c.buttonAccent}; }
|
slider { background-color: ${c.buttonAccent}; }
|
||||||
|
@ -177,21 +197,27 @@ export const PositionSlider = (player, props) => Slider({
|
||||||
}
|
}
|
||||||
}],
|
}],
|
||||||
|
|
||||||
['button-press-event', s => { s.cursor = 'grabbing'; }],
|
['button-press-event', (s) => {
|
||||||
['button-release-event', s => { s.cursor = 'pointer'; }],
|
s.cursor = 'grabbing';
|
||||||
|
}],
|
||||||
|
['button-release-event', (s) => {
|
||||||
|
s.cursor = 'pointer';
|
||||||
|
}],
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
const PlayerButton = ({ player, items, onClick, prop }) => EventBox({
|
const PlayerButton = ({ player, items, onClick, prop }) => EventBox({
|
||||||
child: Button({
|
child: Button({
|
||||||
child: Stack({ items }),
|
|
||||||
onPrimaryClickRelease: () => player[onClick](),
|
|
||||||
properties: [['hovered', false]],
|
properties: [['hovered', false]],
|
||||||
onHover: self => {
|
child: Stack({ items }),
|
||||||
|
|
||||||
|
onPrimaryClickRelease: () => player[onClick](),
|
||||||
|
|
||||||
|
onHover: (self) => {
|
||||||
self._hovered = true;
|
self._hovered = true;
|
||||||
|
|
||||||
if (prop == 'playBackStatus') {
|
if (prop === 'playBackStatus') {
|
||||||
items.forEach(item => {
|
items.forEach((item) => {
|
||||||
item[1].setCss(`
|
item[1].setCss(`
|
||||||
background-color: ${player.colors.value.hoverAccent};
|
background-color: ${player.colors.value.hoverAccent};
|
||||||
color: ${player.colors.value.buttonText};
|
color: ${player.colors.value.buttonText};
|
||||||
|
@ -203,10 +229,11 @@ const PlayerButton = ({ player, items, onClick, prop }) => EventBox({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onHoverLost: self => {
|
|
||||||
|
onHoverLost: (self) => {
|
||||||
self._hovered = false;
|
self._hovered = false;
|
||||||
if (prop == 'playBackStatus') {
|
if (prop === 'playBackStatus') {
|
||||||
items.forEach(item => {
|
items.forEach((item) => {
|
||||||
item[1].setCss(`
|
item[1].setCss(`
|
||||||
background-color: ${player.colors.value.buttonAccent};
|
background-color: ${player.colors.value.buttonAccent};
|
||||||
color: ${player.colors.value.buttonText};
|
color: ${player.colors.value.buttonText};
|
||||||
|
@ -216,22 +243,26 @@ const PlayerButton = ({ player, items, onClick, prop }) => EventBox({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
connections: [
|
connections: [
|
||||||
[player, button => {
|
[player, (button) => {
|
||||||
button.child.shown = `${player[prop]}`;
|
button.child.shown = `${player[prop]}`;
|
||||||
}],
|
}],
|
||||||
|
|
||||||
[player.colors, button => {
|
[player.colors, (button) => {
|
||||||
if (!Mpris.players.find(p => player === p))
|
if (!Mpris.players.find((p) => player === p)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (player.colors.value) {
|
if (player.colors.value) {
|
||||||
if (prop == 'playBackStatus') {
|
const c = player.colors.value;
|
||||||
|
|
||||||
|
if (prop === 'playBackStatus') {
|
||||||
if (button._hovered) {
|
if (button._hovered) {
|
||||||
items.forEach(item => {
|
items.forEach((item) => {
|
||||||
item[1].setCss(`
|
item[1].setCss(`
|
||||||
background-color: ${player.colors.value.hoverAccent};
|
background-color: ${c.hoverAccent};
|
||||||
color: ${player.colors.value.buttonText};
|
color: ${c.buttonText};
|
||||||
min-height: 40px;
|
min-height: 40px;
|
||||||
min-width: 36px;
|
min-width: 36px;
|
||||||
margin-bottom: 1px;
|
margin-bottom: 1px;
|
||||||
|
@ -240,10 +271,10 @@ const PlayerButton = ({ player, items, onClick, prop }) => EventBox({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
items.forEach(item => {
|
items.forEach((item) => {
|
||||||
item[1].setCss(`
|
item[1].setCss(`
|
||||||
background-color: ${player.colors.value.buttonAccent};
|
background-color: ${c.buttonAccent};
|
||||||
color: ${player.colors.value.buttonText};
|
color: ${c.buttonText};
|
||||||
min-height: 42px;
|
min-height: 42px;
|
||||||
min-width: 38px;`);
|
min-width: 38px;`);
|
||||||
});
|
});
|
||||||
|
@ -251,8 +282,8 @@ const PlayerButton = ({ player, items, onClick, prop }) => EventBox({
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
button.setCss(`
|
button.setCss(`
|
||||||
* { color: ${player.colors.value.buttonAccent}; }
|
* { color: ${c.buttonAccent}; }
|
||||||
*:hover { color: ${player.colors.value.hoverAccent}; }
|
*:hover { color: ${c.hoverAccent}; }
|
||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -261,7 +292,7 @@ const PlayerButton = ({ player, items, onClick, prop }) => EventBox({
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const ShuffleButton = player => PlayerButton({
|
export const ShuffleButton = (player) => PlayerButton({
|
||||||
player,
|
player,
|
||||||
items: [
|
items: [
|
||||||
['true', Label({
|
['true', Label({
|
||||||
|
@ -277,7 +308,7 @@ export const ShuffleButton = player => PlayerButton({
|
||||||
prop: 'shuffleStatus',
|
prop: 'shuffleStatus',
|
||||||
});
|
});
|
||||||
|
|
||||||
export const LoopButton = player => PlayerButton({
|
export const LoopButton = (player) => PlayerButton({
|
||||||
player,
|
player,
|
||||||
items: [
|
items: [
|
||||||
['None', Label({
|
['None', Label({
|
||||||
|
@ -297,7 +328,7 @@ export const LoopButton = player => PlayerButton({
|
||||||
prop: 'loopStatus',
|
prop: 'loopStatus',
|
||||||
});
|
});
|
||||||
|
|
||||||
export const PlayPauseButton = player => PlayerButton({
|
export const PlayPauseButton = (player) => PlayerButton({
|
||||||
player,
|
player,
|
||||||
items: [
|
items: [
|
||||||
['Playing', Label({
|
['Playing', Label({
|
||||||
|
@ -317,7 +348,7 @@ export const PlayPauseButton = player => PlayerButton({
|
||||||
prop: 'playBackStatus',
|
prop: 'playBackStatus',
|
||||||
});
|
});
|
||||||
|
|
||||||
export const PreviousButton = player => PlayerButton({
|
export const PreviousButton = (player) => PlayerButton({
|
||||||
player,
|
player,
|
||||||
items: [
|
items: [
|
||||||
['true', Label({
|
['true', Label({
|
||||||
|
@ -333,7 +364,7 @@ export const PreviousButton = player => PlayerButton({
|
||||||
prop: 'canGoPrev',
|
prop: 'canGoPrev',
|
||||||
});
|
});
|
||||||
|
|
||||||
export const NextButton = player => PlayerButton({
|
export const NextButton = (player) => PlayerButton({
|
||||||
player,
|
player,
|
||||||
items: [
|
items: [
|
||||||
['true', Label({
|
['true', Label({
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import Mpris from 'resource:///com/github/Aylur/ags/service/mpris.js';
|
import Mpris from 'resource:///com/github/Aylur/ags/service/mpris.js';
|
||||||
import Variable from 'resource:///com/github/Aylur/ags/variable.js';
|
import Variable from 'resource:///com/github/Aylur/ags/variable.js';
|
||||||
|
|
||||||
import { Box, CenterBox } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Box, CenterBox } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
|
|
||||||
import * as mpris from './mpris.js';
|
import * as mpris from './mpris.js';
|
||||||
|
@ -9,10 +10,11 @@ import Separator from '../misc/separator.js';
|
||||||
const FAVE_PLAYER = 'org.mpris.MediaPlayer2.spotify';
|
const FAVE_PLAYER = 'org.mpris.MediaPlayer2.spotify';
|
||||||
|
|
||||||
|
|
||||||
const Top = player => Box({
|
const Top = (player) => Box({
|
||||||
className: 'top',
|
className: 'top',
|
||||||
hpack: 'start',
|
hpack: 'start',
|
||||||
vpack: 'start',
|
vpack: 'start',
|
||||||
|
|
||||||
children: [
|
children: [
|
||||||
mpris.PlayerIcon(player, {
|
mpris.PlayerIcon(player, {
|
||||||
symbolic: false,
|
symbolic: false,
|
||||||
|
@ -20,12 +22,13 @@ const Top = player => Box({
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
const Center = player => Box({
|
const Center = (player) => Box({
|
||||||
className: 'center',
|
className: 'center',
|
||||||
children: [
|
|
||||||
|
|
||||||
|
children: [
|
||||||
CenterBox({
|
CenterBox({
|
||||||
vertical: true,
|
vertical: true,
|
||||||
|
|
||||||
children: [
|
children: [
|
||||||
Box({
|
Box({
|
||||||
className: 'metadata',
|
className: 'metadata',
|
||||||
|
@ -33,6 +36,7 @@ const Center = player => Box({
|
||||||
hpack: 'start',
|
hpack: 'start',
|
||||||
vpack: 'center',
|
vpack: 'center',
|
||||||
hexpand: true,
|
hexpand: true,
|
||||||
|
|
||||||
children: [
|
children: [
|
||||||
mpris.TitleLabel(player),
|
mpris.TitleLabel(player),
|
||||||
mpris.ArtistLabel(player),
|
mpris.ArtistLabel(player),
|
||||||
|
@ -45,6 +49,7 @@ const Center = player => Box({
|
||||||
|
|
||||||
CenterBox({
|
CenterBox({
|
||||||
vertical: true,
|
vertical: true,
|
||||||
|
|
||||||
children: [
|
children: [
|
||||||
null,
|
null,
|
||||||
mpris.PlayPauseButton(player),
|
mpris.PlayPauseButton(player),
|
||||||
|
@ -55,31 +60,35 @@ const Center = player => Box({
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
const Bottom = player => Box({
|
const SPACING = 8;
|
||||||
|
|
||||||
|
const Bottom = (player) => Box({
|
||||||
className: 'bottom',
|
className: 'bottom',
|
||||||
|
|
||||||
children: [
|
children: [
|
||||||
mpris.PreviousButton(player, {
|
mpris.PreviousButton(player, {
|
||||||
vpack: 'end',
|
vpack: 'end',
|
||||||
hpack: 'start',
|
hpack: 'start',
|
||||||
}),
|
}),
|
||||||
Separator(8),
|
Separator(SPACING),
|
||||||
|
|
||||||
mpris.PositionSlider(player),
|
mpris.PositionSlider(player),
|
||||||
Separator(8),
|
Separator(SPACING),
|
||||||
|
|
||||||
mpris.NextButton(player),
|
mpris.NextButton(player),
|
||||||
Separator(8),
|
Separator(SPACING),
|
||||||
|
|
||||||
mpris.ShuffleButton(player),
|
mpris.ShuffleButton(player),
|
||||||
Separator(8),
|
Separator(SPACING),
|
||||||
|
|
||||||
mpris.LoopButton(player),
|
mpris.LoopButton(player),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
const PlayerBox = player => mpris.CoverArt(player, {
|
const PlayerBox = (player) => mpris.CoverArt(player, {
|
||||||
className: `player ${player.name}`,
|
className: `player ${player.name}`,
|
||||||
hexpand: true,
|
hexpand: true,
|
||||||
|
|
||||||
children: [
|
children: [
|
||||||
Top(player),
|
Top(player),
|
||||||
Center(player),
|
Center(player),
|
||||||
|
@ -89,27 +98,36 @@ const PlayerBox = player => mpris.CoverArt(player, {
|
||||||
|
|
||||||
export default () => Box({
|
export default () => Box({
|
||||||
className: 'media',
|
className: 'media',
|
||||||
|
|
||||||
child: PlayerGesture({
|
child: PlayerGesture({
|
||||||
properties: [
|
properties: [
|
||||||
['players', new Map()],
|
['players', new Map()],
|
||||||
['setup', false],
|
['setup', false],
|
||||||
],
|
],
|
||||||
|
|
||||||
connections: [
|
connections: [
|
||||||
[Mpris, (overlay, busName) => {
|
[Mpris, (overlay, busName) => {
|
||||||
if (overlay._players.has(busName))
|
if (overlay._players.has(busName)) {
|
||||||
return;
|
|
||||||
|
|
||||||
// Sometimes the signal doesn't give the busName
|
|
||||||
if (!busName) {
|
|
||||||
const player = Mpris.players.find(p => !overlay._players.has(p.busName));
|
|
||||||
if (player)
|
|
||||||
busName = player.busName;
|
|
||||||
else
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sometimes the signal doesn't give the busName
|
||||||
|
if (!busName) {
|
||||||
|
const player = Mpris.players.find((p) => {
|
||||||
|
return !overlay._players.has(p.busName);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (player) {
|
||||||
|
busName = player.busName;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Get the one on top so it stays there
|
// Get the one on top so it stays there
|
||||||
var previousFirst = overlay.get_children().at(-1);
|
let previousFirst = overlay.get_children().at(-1);
|
||||||
|
|
||||||
for (const [key, value] of overlay._players.entries()) {
|
for (const [key, value] of overlay._players.entries()) {
|
||||||
if (value === previousFirst) {
|
if (value === previousFirst) {
|
||||||
previousFirst = key;
|
previousFirst = key;
|
||||||
|
@ -118,12 +136,14 @@ export default () => Box({
|
||||||
}
|
}
|
||||||
|
|
||||||
const player = Mpris.getPlayer(busName);
|
const player = Mpris.getPlayer(busName);
|
||||||
|
|
||||||
player.colors = Variable();
|
player.colors = Variable();
|
||||||
|
|
||||||
overlay._players.set(busName, PlayerBox(player));
|
overlay._players.set(busName, PlayerBox(player));
|
||||||
|
|
||||||
const result = [];
|
const result = [];
|
||||||
overlay._players.forEach(widget => {
|
|
||||||
|
overlay._players.forEach((widget) => {
|
||||||
result.push(widget);
|
result.push(widget);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -131,21 +151,29 @@ export default () => Box({
|
||||||
|
|
||||||
// Select favorite player at startup
|
// Select favorite player at startup
|
||||||
if (!overlay._setup && overlay._players.has(FAVE_PLAYER)) {
|
if (!overlay._setup && overlay._players.has(FAVE_PLAYER)) {
|
||||||
overlay.reorder_overlay(overlay._players.get(FAVE_PLAYER), -1);
|
overlay.reorder_overlay(
|
||||||
|
overlay._players.get(FAVE_PLAYER),
|
||||||
|
-1,
|
||||||
|
);
|
||||||
overlay._setup = true;
|
overlay._setup = true;
|
||||||
}
|
}
|
||||||
else if (overlay._players.get(previousFirst)) {
|
else if (overlay._players.get(previousFirst)) {
|
||||||
overlay.reorder_overlay(overlay._players.get(previousFirst), -1);
|
overlay.reorder_overlay(
|
||||||
|
overlay._players.get(previousFirst),
|
||||||
|
-1,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}, 'player-added'],
|
}, 'player-added'],
|
||||||
|
|
||||||
|
|
||||||
[Mpris, (overlay, busName) => {
|
[Mpris, (overlay, busName) => {
|
||||||
if (!busName || !overlay._players.has(busName))
|
if (!busName || !overlay._players.has(busName)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Get the one on top so it stays there
|
// Get the one on top so it stays there
|
||||||
var previousFirst = overlay.get_children().at(-1);
|
let previousFirst = overlay.get_children().at(-1);
|
||||||
|
|
||||||
for (const [key, value] of overlay._players.entries()) {
|
for (const [key, value] of overlay._players.entries()) {
|
||||||
if (value === previousFirst) {
|
if (value === previousFirst) {
|
||||||
previousFirst = key;
|
previousFirst = key;
|
||||||
|
@ -156,14 +184,19 @@ export default () => Box({
|
||||||
overlay._players.delete(busName);
|
overlay._players.delete(busName);
|
||||||
|
|
||||||
const result = [];
|
const result = [];
|
||||||
overlay._players.forEach(widget => {
|
|
||||||
|
overlay._players.forEach((widget) => {
|
||||||
result.push(widget);
|
result.push(widget);
|
||||||
});
|
});
|
||||||
|
|
||||||
overlay.overlays = result;
|
overlay.overlays = result;
|
||||||
|
|
||||||
if (overlay._players.has(previousFirst))
|
if (overlay._players.has(previousFirst)) {
|
||||||
overlay.reorder_overlay(overlay._players.get(previousFirst), -1);
|
overlay.reorder_overlay(
|
||||||
|
overlay._players.get(previousFirst),
|
||||||
|
-1,
|
||||||
|
);
|
||||||
|
}
|
||||||
}, 'player-closed'],
|
}, 'player-closed'],
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -19,8 +19,9 @@ const micIcons = {
|
||||||
|
|
||||||
export const SpeakerIcon = Variable();
|
export const SpeakerIcon = Variable();
|
||||||
Audio.connect('speaker-changed', () => {
|
Audio.connect('speaker-changed', () => {
|
||||||
if (!Audio.speaker)
|
if (!Audio.speaker) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (Audio.speaker.stream.isMuted) {
|
if (Audio.speaker.stream.isMuted) {
|
||||||
SpeakerIcon.value = speakerIcons[0];
|
SpeakerIcon.value = speakerIcons[0];
|
||||||
|
@ -29,16 +30,18 @@ Audio.connect('speaker-changed', () => {
|
||||||
const vol = Audio.speaker.volume * 100;
|
const vol = Audio.speaker.volume * 100;
|
||||||
|
|
||||||
for (const threshold of [-1, 0, 33, 66, 100]) {
|
for (const threshold of [-1, 0, 33, 66, 100]) {
|
||||||
if (vol > threshold + 1)
|
if (vol > threshold + 1) {
|
||||||
SpeakerIcon.value = speakerIcons[threshold + 1];
|
SpeakerIcon.value = speakerIcons[threshold + 1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export const MicIcon = Variable();
|
export const MicIcon = Variable();
|
||||||
Audio.connect('microphone-changed', () => {
|
Audio.connect('microphone-changed', () => {
|
||||||
if (!Audio.microphone)
|
if (!Audio.microphone) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (Audio.microphone.stream.isMuted) {
|
if (Audio.microphone.stream.isMuted) {
|
||||||
MicIcon.value = micIcons[0];
|
MicIcon.value = micIcons[0];
|
||||||
|
@ -47,8 +50,9 @@ Audio.connect('microphone-changed', () => {
|
||||||
const vol = Audio.microphone.volume * 100;
|
const vol = Audio.microphone.volume * 100;
|
||||||
|
|
||||||
for (const threshold of [-1, 0, 33, 66]) {
|
for (const threshold of [-1, 0, 33, 66]) {
|
||||||
if (vol > threshold + 1)
|
if (vol > threshold + 1) {
|
||||||
MicIcon.value = micIcons[threshold + 1];
|
MicIcon.value = micIcons[threshold + 1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,8 +3,8 @@ import App from 'resource:///com/github/Aylur/ags/app.js';
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
Array.from(App.windows)
|
Array.from(App.windows)
|
||||||
.filter(w => w[1].closeOnUnfocus && w[1].closeOnUnfocus !== 'stay')
|
.filter((w) => w[1].closeOnUnfocus && w[1].closeOnUnfocus !== 'stay')
|
||||||
.forEach(w => {
|
.forEach((w) => {
|
||||||
App.closeWindow(w[0]);
|
App.closeWindow(w[0]);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import Variable from 'resource:///com/github/Aylur/ags/variable.js';
|
import Variable from 'resource:///com/github/Aylur/ags/variable.js';
|
||||||
|
|
||||||
import { Button, EventBox } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Button, EventBox } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
|
|
||||||
import Gtk from 'gi://Gtk';
|
import Gtk from 'gi://Gtk';
|
||||||
|
@ -7,7 +8,7 @@ import Gtk from 'gi://Gtk';
|
||||||
// TODO: wrap in another EventBox for disabled cursor
|
// TODO: wrap in another EventBox for disabled cursor
|
||||||
export default ({
|
export default ({
|
||||||
isButton = false,
|
isButton = false,
|
||||||
onPrimaryClickRelease = () => {},
|
onPrimaryClickRelease = () => { /**/ },
|
||||||
...props
|
...props
|
||||||
}) => {
|
}) => {
|
||||||
// Make this variable to know if the function should
|
// Make this variable to know if the function should
|
||||||
|
@ -17,12 +18,13 @@ export default ({
|
||||||
const properties = {
|
const properties = {
|
||||||
...props,
|
...props,
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
onPrimaryClickRelease: self => {
|
onPrimaryClickRelease: (self) => {
|
||||||
// Every click, do a one shot connect to
|
// Every click, do a one shot connect to
|
||||||
// CanRun to wait for location of click
|
// CanRun to wait for location of click
|
||||||
const id = CanRun.connect('changed', () => {
|
const id = CanRun.connect('changed', () => {
|
||||||
if (CanRun.value)
|
if (CanRun.value) {
|
||||||
onPrimaryClickRelease(self);
|
onPrimaryClickRelease(self);
|
||||||
|
}
|
||||||
|
|
||||||
CanRun.disconnect(id);
|
CanRun.disconnect(id);
|
||||||
});
|
});
|
||||||
|
@ -30,10 +32,13 @@ export default ({
|
||||||
};
|
};
|
||||||
|
|
||||||
let widget;
|
let widget;
|
||||||
if (!isButton)
|
|
||||||
widget = EventBox(properties);
|
if (isButton) {
|
||||||
else
|
|
||||||
widget = Button(properties);
|
widget = Button(properties);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
widget = EventBox(properties);
|
||||||
|
}
|
||||||
|
|
||||||
const gesture = Gtk.GestureLongPress.new(widget);
|
const gesture = Gtk.GestureLongPress.new(widget);
|
||||||
|
|
||||||
|
@ -42,8 +47,9 @@ export default ({
|
||||||
const x = pointer[1];
|
const x = pointer[1];
|
||||||
const y = pointer[2];
|
const y = pointer[2];
|
||||||
|
|
||||||
if ((!x || !y) || x === 0 && y === 0)
|
if ((!x || !y) || (x === 0 && y === 0)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
CanRun.value = !(
|
CanRun.value = !(
|
||||||
x > widget.get_allocated_width() ||
|
x > widget.get_allocated_width() ||
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import App from 'resource:///com/github/Aylur/ags/app.js';
|
import App from 'resource:///com/github/Aylur/ags/app.js';
|
||||||
|
|
||||||
import { Revealer, Box, Window } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Revealer, Box, Window } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,8 +10,8 @@ export default ({
|
||||||
|
|
||||||
// Optional: execute a function whenever
|
// Optional: execute a function whenever
|
||||||
// the window pops up or goes away
|
// the window pops up or goes away
|
||||||
onOpen = () => {},
|
onOpen = () => { /**/ },
|
||||||
onClose = () => {},
|
onClose = () => { /**/ },
|
||||||
|
|
||||||
// Window props
|
// Window props
|
||||||
name,
|
name,
|
||||||
|
@ -29,8 +30,9 @@ export default ({
|
||||||
// Add way to make window open on startup
|
// Add way to make window open on startup
|
||||||
setup: () => {
|
setup: () => {
|
||||||
const id = App.connect('config-parsed', () => {
|
const id = App.connect('config-parsed', () => {
|
||||||
if (visible)
|
if (visible) {
|
||||||
App.openWindow(name);
|
App.openWindow(name);
|
||||||
|
}
|
||||||
App.disconnect(id);
|
App.disconnect(id);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -38,32 +40,39 @@ export default ({
|
||||||
// Wrapping the revealer inside a box is needed
|
// Wrapping the revealer inside a box is needed
|
||||||
// to allocate some space for it even when not revealed
|
// to allocate some space for it even when not revealed
|
||||||
child: Box({
|
child: Box({
|
||||||
css: `min-height:1px;
|
css: `
|
||||||
|
min-height:1px;
|
||||||
min-width:1px;
|
min-width:1px;
|
||||||
padding: 1px;`,
|
padding: 1px;
|
||||||
|
`,
|
||||||
child: Revealer({
|
child: Revealer({
|
||||||
transition,
|
transition,
|
||||||
transitionDuration,
|
transitionDuration,
|
||||||
connections: [[App, (rev, currentName, visible) => {
|
|
||||||
if (currentName === name) {
|
|
||||||
rev.revealChild = visible;
|
|
||||||
|
|
||||||
if (visible)
|
connections: [[App, (rev, currentName, isOpen) => {
|
||||||
|
if (currentName === name) {
|
||||||
|
rev.revealChild = isOpen;
|
||||||
|
|
||||||
|
if (isOpen) {
|
||||||
onOpen(child);
|
onOpen(child);
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
onClose(child);
|
onClose(child);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}]],
|
}]],
|
||||||
|
|
||||||
child: child || Box(),
|
child: child || Box(),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Make getting the original child passed in
|
// Make getting the original child passed in this
|
||||||
// this function easier when making more code
|
// function easier when making more code for the widget
|
||||||
// for the widget
|
|
||||||
window.getChild = () => window.child.children[0].child;
|
window.getChild = () => window.child.children[0].child;
|
||||||
window.setChild = newChild => window.child.children[0].child = newChild;
|
window.setChild = (newChild) => {
|
||||||
|
window.child.children[0].child = newChild;
|
||||||
|
};
|
||||||
|
|
||||||
// This is for my custom pointers.js
|
// This is for my custom pointers.js
|
||||||
window.closeOnUnfocus = closeOnUnfocus;
|
window.closeOnUnfocus = closeOnUnfocus;
|
||||||
|
|
|
@ -1,17 +1,13 @@
|
||||||
import { Box } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Box } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
|
|
||||||
|
|
||||||
export default (size, { vertical = false, css = '', ...props } = {}) => {
|
export default (size, {
|
||||||
if (vertical) {
|
vertical = false,
|
||||||
|
css = '',
|
||||||
|
...props
|
||||||
|
} = {}) => {
|
||||||
return Box({
|
return Box({
|
||||||
css: `min-height: ${size}px; ${css}`,
|
css: `${vertical ? 'min-height' : 'min-width'}: ${size}px; ${css}`,
|
||||||
...props,
|
...props,
|
||||||
});
|
});
|
||||||
}
|
|
||||||
else {
|
|
||||||
return Box({
|
|
||||||
css: `min-width: ${size}px; ${css}`,
|
|
||||||
...props,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,54 +2,62 @@ import Applications from 'resource:///com/github/Aylur/ags/service/applications.
|
||||||
import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
|
import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
|
||||||
import Notifications from 'resource:///com/github/Aylur/ags/service/notifications.js';
|
import Notifications from 'resource:///com/github/Aylur/ags/service/notifications.js';
|
||||||
import Variable from 'resource:///com/github/Aylur/ags/variable.js';
|
import Variable from 'resource:///com/github/Aylur/ags/variable.js';
|
||||||
|
|
||||||
import { Box, Icon, Label, Button } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Box, Icon, Label, Button } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
import { lookUpIcon } from 'resource:///com/github/Aylur/ags/utils.js';
|
import { lookUpIcon } from 'resource:///com/github/Aylur/ags/utils.js';
|
||||||
|
|
||||||
import GLib from 'gi://GLib';
|
import GLib from 'gi://GLib';
|
||||||
|
|
||||||
const setTime = time => {
|
const setTime = (time) => {
|
||||||
return GLib.DateTime
|
return GLib.DateTime
|
||||||
.new_from_unix_local(time)
|
.new_from_unix_local(time)
|
||||||
.format('%H:%M');
|
.format('%H:%M');
|
||||||
};
|
};
|
||||||
|
|
||||||
const getDragState = box => box.get_parent().get_parent()
|
const getDragState = (box) => box.get_parent().get_parent()
|
||||||
.get_parent().get_parent().get_parent()._dragging;
|
.get_parent().get_parent().get_parent()._dragging;
|
||||||
|
|
||||||
import Gesture from './gesture.js';
|
import Gesture from './gesture.js';
|
||||||
import EventBox from '../misc/cursorbox.js';
|
import EventBox from '../misc/cursorbox.js';
|
||||||
|
|
||||||
|
|
||||||
const NotificationIcon = notif => {
|
const NotificationIcon = (notif) => {
|
||||||
let iconCmd = () => {};
|
let iconCmd = () => { /**/ };
|
||||||
|
|
||||||
if (Applications.query(notif.appEntry).length > 0) {
|
if (Applications.query(notif.appEntry).length > 0) {
|
||||||
const app = Applications.query(notif.appEntry)[0];
|
const app = Applications.query(notif.appEntry)[0];
|
||||||
|
|
||||||
let wmClass = app.app.get_string('StartupWMClass');
|
let wmClass = app.app.get_string('StartupWMClass');
|
||||||
if (app.app.get_filename().includes('discord'))
|
|
||||||
|
if (app.app.get_filename().includes('discord')) {
|
||||||
wmClass = 'discord';
|
wmClass = 'discord';
|
||||||
|
}
|
||||||
|
|
||||||
if (wmClass != null) {
|
if (wmClass != null) {
|
||||||
iconCmd = box => {
|
iconCmd = (box) => {
|
||||||
if (!getDragState(box)) {
|
if (!getDragState(box)) {
|
||||||
if (wmClass === 'thunderbird') {
|
if (wmClass === 'thunderbird') {
|
||||||
Hyprland.sendMessage('dispatch togglespecialworkspace thunder');
|
Hyprland.sendMessage('dispatch ' +
|
||||||
|
'togglespecialworkspace thunder');
|
||||||
}
|
}
|
||||||
else if (wmClass === 'Spotify') {
|
else if (wmClass === 'Spotify') {
|
||||||
Hyprland.sendMessage('dispatch togglespecialworkspace spot');
|
Hyprland.sendMessage('dispatch ' +
|
||||||
|
'togglespecialworkspace spot');
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Hyprland.sendMessage('j/clients').then(out => {
|
Hyprland.sendMessage('j/clients').then((out) => {
|
||||||
out = JSON.parse(out);
|
out = JSON.parse(out);
|
||||||
const classes = [];
|
const classes = [];
|
||||||
|
|
||||||
for (const key of out) {
|
for (const key of out) {
|
||||||
if (key.class)
|
if (key.class) {
|
||||||
classes.push(key.class);
|
classes.push(key.class);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (classes.includes(wmClass)) {
|
if (classes.includes(wmClass)) {
|
||||||
Hyprland.sendMessage(`dispatch focuswindow ^(${wmClass})`);
|
Hyprland.sendMessage('dispatch ' +
|
||||||
|
`focuswindow ^(${wmClass})`);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Hyprland.sendMessage('[[BATCH]] ' +
|
Hyprland.sendMessage('[[BATCH]] ' +
|
||||||
|
@ -69,6 +77,7 @@ const NotificationIcon = notif => {
|
||||||
if (notif.image) {
|
if (notif.image) {
|
||||||
return EventBox({
|
return EventBox({
|
||||||
onPrimaryClickRelease: iconCmd,
|
onPrimaryClickRelease: iconCmd,
|
||||||
|
|
||||||
child: Box({
|
child: Box({
|
||||||
vpack: 'start',
|
vpack: 'start',
|
||||||
hexpand: false,
|
hexpand: false,
|
||||||
|
@ -86,22 +95,28 @@ const NotificationIcon = notif => {
|
||||||
}
|
}
|
||||||
|
|
||||||
let icon = 'dialog-information-symbolic';
|
let icon = 'dialog-information-symbolic';
|
||||||
if (lookUpIcon(notif.appIcon))
|
|
||||||
|
if (lookUpIcon(notif.appIcon)) {
|
||||||
icon = notif.appIcon;
|
icon = notif.appIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (lookUpIcon(notif.appEntry))
|
if (lookUpIcon(notif.appEntry)) {
|
||||||
icon = notif.appEntry;
|
icon = notif.appEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return EventBox({
|
return EventBox({
|
||||||
onPrimaryClickRelease: iconCmd,
|
onPrimaryClickRelease: iconCmd,
|
||||||
|
|
||||||
child: Box({
|
child: Box({
|
||||||
vpack: 'start',
|
vpack: 'start',
|
||||||
hexpand: false,
|
hexpand: false,
|
||||||
className: 'icon',
|
className: 'icon',
|
||||||
css: `min-width: 78px;
|
css: `
|
||||||
min-height: 78px;`,
|
min-width: 78px;
|
||||||
|
min-height: 78px;
|
||||||
|
`,
|
||||||
children: [Icon({
|
children: [Icon({
|
||||||
icon, size: 58,
|
icon, size: 58,
|
||||||
hpack: 'center',
|
hpack: 'center',
|
||||||
|
@ -120,22 +135,24 @@ export const HasNotifs = Variable(false);
|
||||||
export const Notification = ({
|
export const Notification = ({
|
||||||
notif,
|
notif,
|
||||||
slideIn = 'Left',
|
slideIn = 'Left',
|
||||||
command = () => {},
|
command = () => { /**/ },
|
||||||
} = {}) => {
|
} = {}) => {
|
||||||
if (!notif)
|
if (!notif) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
HasNotifs.value = Notifications.notifications.length > 0;
|
|
||||||
|
|
||||||
const BlockedApps = [
|
const BlockedApps = [
|
||||||
'Spotify',
|
'Spotify',
|
||||||
];
|
];
|
||||||
|
|
||||||
if (BlockedApps.find(app => app == notif.appName)) {
|
if (BlockedApps.find((app) => app === notif.appName)) {
|
||||||
notif.close();
|
notif.close();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HasNotifs.value = Notifications.notifications.length > 0;
|
||||||
|
|
||||||
// Init notif
|
// Init notif
|
||||||
const notifWidget = Gesture({
|
const notifWidget = Gesture({
|
||||||
command,
|
command,
|
||||||
|
@ -147,10 +164,12 @@ export const Notification = ({
|
||||||
notifWidget.child.add(Box({
|
notifWidget.child.add(Box({
|
||||||
className: `notification ${notif.urgency}`,
|
className: `notification ${notif.urgency}`,
|
||||||
vexpand: false,
|
vexpand: false,
|
||||||
|
|
||||||
// Notification
|
// Notification
|
||||||
child: Box({
|
child: Box({
|
||||||
vertical: true,
|
vertical: true,
|
||||||
children: [
|
children: [
|
||||||
|
|
||||||
// Content
|
// Content
|
||||||
Box({
|
Box({
|
||||||
children: [
|
children: [
|
||||||
|
@ -159,9 +178,12 @@ export const Notification = ({
|
||||||
hexpand: true,
|
hexpand: true,
|
||||||
vertical: true,
|
vertical: true,
|
||||||
children: [
|
children: [
|
||||||
|
|
||||||
// Top of Content
|
// Top of Content
|
||||||
Box({
|
Box({
|
||||||
children: [
|
children: [
|
||||||
|
|
||||||
|
// Title
|
||||||
Label({
|
Label({
|
||||||
className: 'title',
|
className: 'title',
|
||||||
xalign: 0,
|
xalign: 0,
|
||||||
|
@ -171,23 +193,31 @@ export const Notification = ({
|
||||||
truncate: 'end',
|
truncate: 'end',
|
||||||
wrap: true,
|
wrap: true,
|
||||||
label: notif.summary,
|
label: notif.summary,
|
||||||
useMarkup: notif.summary.startsWith('<'),
|
useMarkup: notif.summary
|
||||||
|
.startsWith('<'),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
// Time
|
||||||
Label({
|
Label({
|
||||||
className: 'time',
|
className: 'time',
|
||||||
vpack: 'start',
|
vpack: 'start',
|
||||||
label: setTime(notif.time),
|
label: setTime(notif.time),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
// Close button
|
||||||
EventBox({
|
EventBox({
|
||||||
child: Button({
|
child: Button({
|
||||||
className: 'close-button',
|
className: 'close-button',
|
||||||
vpack: 'start',
|
vpack: 'start',
|
||||||
onClicked: () => notif.close(),
|
onClicked: () => notif.close(),
|
||||||
child: Icon('window-close-symbolic'),
|
child: Icon('window-close' +
|
||||||
|
'-symbolic'),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
// Description
|
||||||
Label({
|
Label({
|
||||||
className: 'description',
|
className: 'description',
|
||||||
hexpand: true,
|
hexpand: true,
|
||||||
|
@ -201,10 +231,11 @@ export const Notification = ({
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
// Actions
|
// Actions
|
||||||
Box({
|
Box({
|
||||||
className: 'actions',
|
className: 'actions',
|
||||||
children: notif.actions.map(action => Button({
|
children: notif.actions.map((action) => Button({
|
||||||
className: 'action-button',
|
className: 'action-button',
|
||||||
onClicked: () => notif.invoke(action.id),
|
onClicked: () => notif.invoke(action.id),
|
||||||
hexpand: true,
|
hexpand: true,
|
||||||
|
@ -214,5 +245,6 @@ export const Notification = ({
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return notifWidget;
|
return notifWidget;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import Notifications from 'resource:///com/github/Aylur/ags/service/notifications.js';
|
import Notifications from 'resource:///com/github/Aylur/ags/service/notifications.js';
|
||||||
|
|
||||||
import { Button, Label, Box, Icon, Scrollable, Revealer } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Button, Label, Box, Icon, Scrollable, Revealer } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
|
|
||||||
import { Notification, HasNotifs } from './base.js';
|
import { Notification, HasNotifs } from './base.js';
|
||||||
|
@ -7,9 +8,7 @@ import EventBox from '../misc/cursorbox.js';
|
||||||
|
|
||||||
|
|
||||||
const addNotif = (box, notif) => {
|
const addNotif = (box, notif) => {
|
||||||
if (!notif)
|
if (notif) {
|
||||||
return;
|
|
||||||
|
|
||||||
const NewNotif = Notification({
|
const NewNotif = Notification({
|
||||||
notif,
|
notif,
|
||||||
slideIn: 'Right',
|
slideIn: 'Right',
|
||||||
|
@ -20,6 +19,7 @@ const addNotif = (box, notif) => {
|
||||||
box.pack_end(NewNotif, false, false, 0);
|
box.pack_end(NewNotif, false, false, 0);
|
||||||
box.show_all();
|
box.show_all();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const NotificationList = () => Box({
|
const NotificationList = () => Box({
|
||||||
|
@ -30,17 +30,23 @@ const NotificationList = () => Box({
|
||||||
connections: [
|
connections: [
|
||||||
[Notifications, (box, id) => {
|
[Notifications, (box, id) => {
|
||||||
// Handle cached notifs
|
// Handle cached notifs
|
||||||
if (box.children.length == 0)
|
if (box.children.length === 0) {
|
||||||
Notifications.notifications.forEach(n => addNotif(box, n));
|
Notifications.notifications.forEach((n) => {
|
||||||
|
addNotif(box, n);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
else if (id)
|
else if (id) {
|
||||||
addNotif(box, Notifications.getNotification(id));
|
addNotif(box, Notifications.getNotification(id));
|
||||||
|
}
|
||||||
}, 'notified'],
|
}, 'notified'],
|
||||||
|
|
||||||
[Notifications, (box, id) => {
|
[Notifications, (box, id) => {
|
||||||
const notif = box.children.find(ch => ch._id === id);
|
const notif = box.children.find((ch) => ch._id === id);
|
||||||
if (notif?.sensitive)
|
|
||||||
|
if (notif?.sensitive) {
|
||||||
notif.slideAway('Right');
|
notif.slideAway('Right');
|
||||||
|
}
|
||||||
}, 'closed'],
|
}, 'closed'],
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
@ -54,9 +60,10 @@ const ClearButton = () => EventBox({
|
||||||
children: [
|
children: [
|
||||||
Label('Clear '),
|
Label('Clear '),
|
||||||
Icon({
|
Icon({
|
||||||
connections: [[Notifications, self => {
|
connections: [[Notifications, (self) => {
|
||||||
self.icon = Notifications.notifications.length > 0
|
self.icon = Notifications.notifications.length > 0 ?
|
||||||
? 'user-trash-full-symbolic' : 'user-trash-symbolic';
|
'user-trash-full-symbolic' :
|
||||||
|
'user-trash-symbolic';
|
||||||
}]],
|
}]],
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
@ -78,7 +85,7 @@ const Header = () => Box({
|
||||||
|
|
||||||
const Placeholder = () => Revealer({
|
const Placeholder = () => Revealer({
|
||||||
transition: 'crossfade',
|
transition: 'crossfade',
|
||||||
binds: [['revealChild', HasNotifs, 'value', value => !value]],
|
binds: [['revealChild', HasNotifs, 'value', (value) => !value]],
|
||||||
child: Box({
|
child: Box({
|
||||||
className: 'placeholder',
|
className: 'placeholder',
|
||||||
vertical: true,
|
vertical: true,
|
||||||
|
@ -118,9 +125,12 @@ const NotificationCenterWidget = () => Box({
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const TOP_MARGIN = 6;
|
||||||
|
const RIGHT_MARGIN = 60;
|
||||||
|
|
||||||
export default () => PopupWindow({
|
export default () => PopupWindow({
|
||||||
name: 'notification-center',
|
name: 'notification-center',
|
||||||
anchor: ['top', 'right'],
|
anchor: ['top', 'right'],
|
||||||
margins: [6, 60, 0, 0],
|
margins: [TOP_MARGIN, RIGHT_MARGIN, 0, 0],
|
||||||
child: NotificationCenterWidget(),
|
child: NotificationCenterWidget(),
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import Notifications from 'resource:///com/github/Aylur/ags/service/notifications.js';
|
import Notifications from 'resource:///com/github/Aylur/ags/service/notifications.js';
|
||||||
|
|
||||||
import { Box, EventBox } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Box, EventBox } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
import { timeout } from 'resource:///com/github/Aylur/ags/utils.js';
|
import { timeout } from 'resource:///com/github/Aylur/ags/utils.js';
|
||||||
|
|
||||||
|
@ -6,26 +7,30 @@ import { HasNotifs } from './base.js';
|
||||||
|
|
||||||
import Gtk from 'gi://Gtk';
|
import Gtk from 'gi://Gtk';
|
||||||
|
|
||||||
|
const MAX_OFFSET = 200;
|
||||||
|
const OFFSCREEN = 300;
|
||||||
|
const ANIM_DURATION = 500;
|
||||||
|
const SLIDE_MIN_THRESHOLD = 10;
|
||||||
|
|
||||||
|
|
||||||
export default ({
|
export default ({
|
||||||
id,
|
id,
|
||||||
slideIn = 'Left',
|
slideIn = 'Left',
|
||||||
maxOffset = 200,
|
command = () => { /**/ },
|
||||||
startMargin = 0,
|
|
||||||
endMargin = 300,
|
|
||||||
command = () => {},
|
|
||||||
...props
|
...props
|
||||||
}) => {
|
}) => {
|
||||||
const widget = EventBox({
|
const widget = EventBox({
|
||||||
...props,
|
...props,
|
||||||
cursor: 'grab',
|
cursor: 'grab',
|
||||||
onHover: self => {
|
onHover: (self) => {
|
||||||
if (!self._hovered)
|
if (!self._hovered) {
|
||||||
self._hovered = true;
|
self._hovered = true;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onHoverLost: self => {
|
onHoverLost: (self) => {
|
||||||
if (self._hovered)
|
if (self._hovered) {
|
||||||
self._hovered = false;
|
self._hovered = false;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -40,33 +45,42 @@ export default ({
|
||||||
const TRANSITION = 'transition: margin 0.5s ease, opacity 0.5s ease;';
|
const TRANSITION = 'transition: margin 0.5s ease, opacity 0.5s ease;';
|
||||||
const SQUEEZED = 'margin-bottom: -70px; margin-top: -70px;';
|
const SQUEEZED = 'margin-bottom: -70px; margin-top: -70px;';
|
||||||
const MAX_LEFT = `
|
const MAX_LEFT = `
|
||||||
margin-left: -${Number(maxOffset + endMargin)}px;
|
margin-left: -${Number(MAX_OFFSET + OFFSCREEN)}px;
|
||||||
margin-right: ${Number(maxOffset + endMargin)}px;
|
margin-right: ${Number(MAX_OFFSET + OFFSCREEN)}px;
|
||||||
`;
|
`;
|
||||||
const MAX_RIGHT = `
|
const MAX_RIGHT = `
|
||||||
margin-left: ${Number(maxOffset + endMargin)}px;
|
margin-left: ${Number(MAX_OFFSET + OFFSCREEN)}px;
|
||||||
margin-right: -${Number(maxOffset + endMargin)}px;
|
margin-right: -${Number(MAX_OFFSET + OFFSCREEN)}px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const slideLeft = `${TRANSITION} ${MAX_LEFT} margin-top: 0px; margin-bottom: 0px; opacity: 0;`;
|
const slideLeft = `${TRANSITION} ${MAX_LEFT}
|
||||||
|
margin-top: 0px;
|
||||||
|
margin-bottom: 0px;
|
||||||
|
opacity: 0;`;
|
||||||
const squeezeLeft = `${TRANSITION} ${MAX_LEFT} ${SQUEEZED} opacity: 0;`;
|
const squeezeLeft = `${TRANSITION} ${MAX_LEFT} ${SQUEEZED} opacity: 0;`;
|
||||||
const slideRight = `${TRANSITION} ${MAX_RIGHT} margin-top: 0px; margin-bottom: 0px; opacity: 0;`;
|
|
||||||
|
const slideRight = `${TRANSITION} ${MAX_RIGHT}
|
||||||
|
margin-top: 0px;
|
||||||
|
margin-bottom: 0px;
|
||||||
|
opacity: 0;`;
|
||||||
const squeezeRight = `${TRANSITION} ${MAX_RIGHT} ${SQUEEZED} opacity: 0;`;
|
const squeezeRight = `${TRANSITION} ${MAX_RIGHT} ${SQUEEZED} opacity: 0;`;
|
||||||
|
|
||||||
const defaultStyle = `${TRANSITION} margin: unset; opacity: 1;`;
|
const defaultStyle = `${TRANSITION} margin: unset; opacity: 1;`;
|
||||||
|
|
||||||
|
|
||||||
// Notif methods
|
// Notif methods
|
||||||
widget.slideAway = side => {
|
widget.slideAway = (side) => {
|
||||||
// Slide away
|
// Slide away
|
||||||
widget.child.setCss(side === 'Left' ? slideLeft : slideRight);
|
widget.child.setCss(side === 'Left' ? slideLeft : slideRight);
|
||||||
|
|
||||||
// Makie it uninteractable
|
// Makie it uninteractable
|
||||||
widget.sensitive = false;
|
widget.sensitive = false;
|
||||||
|
|
||||||
timeout(400, () => {
|
timeout(ANIM_DURATION - 100, () => {
|
||||||
// Reduce height after sliding away
|
// Reduce height after sliding away
|
||||||
widget.child?.setCss(side === 'Left' ? squeezeLeft : squeezeRight);
|
widget.child?.setCss(side === 'Left' ? squeezeLeft : squeezeRight);
|
||||||
|
|
||||||
timeout(500, () => {
|
timeout(ANIM_DURATION, () => {
|
||||||
// Kill notif and update HasNotifs after anim is done
|
// Kill notif and update HasNotifs after anim is done
|
||||||
command();
|
command();
|
||||||
HasNotifs.value = Notifications.notifications.length > 0;
|
HasNotifs.value = Notifications.notifications.length > 0;
|
||||||
|
@ -80,17 +94,20 @@ export default ({
|
||||||
connections: [
|
connections: [
|
||||||
|
|
||||||
// When dragging
|
// When dragging
|
||||||
[gesture, self => {
|
[gesture, (self) => {
|
||||||
var offset = gesture.get_offset()[1];
|
let offset = gesture.get_offset()[1];
|
||||||
if (offset === 0)
|
|
||||||
|
if (offset === 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Slide right
|
// Slide right
|
||||||
if (offset > 0) {
|
if (offset > 0) {
|
||||||
self.setCss(`
|
self.setCss(`
|
||||||
margin-top: 0px; margin-bottom: 0px; opacity: 1; transition: none;
|
margin-top: 0px; margin-bottom: 0px;
|
||||||
margin-left: ${Number(offset + startMargin)}px;
|
opacity: 1; transition: none;
|
||||||
margin-right: -${Number(offset + startMargin)}px;
|
margin-left: ${offset}px;
|
||||||
|
margin-right: -${offset}px;
|
||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,45 +115,51 @@ export default ({
|
||||||
else {
|
else {
|
||||||
offset = Math.abs(offset);
|
offset = Math.abs(offset);
|
||||||
self.setCss(`
|
self.setCss(`
|
||||||
margin-top: 0px; margin-bottom: 0px; opacity: 1; transition: none;
|
margin-top: 0px; margin-bottom: 0px;
|
||||||
margin-right: ${Number(offset + startMargin)}px;
|
opacity: 1; transition: none;
|
||||||
margin-left: -${Number(offset + startMargin)}px;
|
margin-right: ${offset}px;
|
||||||
|
margin-left: -${offset}px;
|
||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put a threshold on if a click is actually dragging
|
// Put a threshold on if a click is actually dragging
|
||||||
widget._dragging = Math.abs(offset) > 10;
|
widget._dragging = Math.abs(offset) > SLIDE_MIN_THRESHOLD;
|
||||||
widget.cursor = 'grabbing';
|
widget.cursor = 'grabbing';
|
||||||
}, 'drag-update'],
|
}, 'drag-update'],
|
||||||
|
|
||||||
|
|
||||||
// On drag end
|
// On drag end
|
||||||
[gesture, self => {
|
[gesture, (self) => {
|
||||||
// Make it slide in on init
|
// Make it slide in on init
|
||||||
if (!widget.ready) {
|
if (!widget.ready) {
|
||||||
// Reverse of slideAway, so it started at squeeze, then we go to slide
|
// Reverse of slideAway, so it started at squeeze, then we go to slide
|
||||||
self.setCss(slideIn === 'Left' ? slideLeft : slideRight);
|
self.setCss(slideIn === 'Left' ? slideLeft : slideRight);
|
||||||
|
|
||||||
timeout(500, () => {
|
timeout(ANIM_DURATION, () => {
|
||||||
// Then we got to center
|
// Then we go to center
|
||||||
self.setCss(defaultStyle);
|
self.setCss(defaultStyle);
|
||||||
timeout(500, () => widget.ready = true);
|
timeout(ANIM_DURATION, () => {
|
||||||
|
widget.ready = true;
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const offset = gesture.get_offset()[1];
|
const offset = gesture.get_offset()[1];
|
||||||
|
|
||||||
// If crosses threshold after letting go, slide away
|
// If crosses threshold after letting go, slide away
|
||||||
if (Math.abs(offset) > maxOffset) {
|
if (Math.abs(offset) > MAX_OFFSET) {
|
||||||
if (offset > 0)
|
if (offset > 0) {
|
||||||
widget.slideAway('Right');
|
widget.slideAway('Right');
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
widget.slideAway('Left');
|
widget.slideAway('Left');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
self.setCss(defaultStyle);
|
self.setCss(defaultStyle);
|
||||||
widget.cursor = 'grab',
|
widget.cursor = 'grab';
|
||||||
widget._dragging = false;
|
widget._dragging = false;
|
||||||
}
|
}
|
||||||
}, 'drag-end'],
|
}, 'drag-end'],
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import Notifications from 'resource:///com/github/Aylur/ags/service/notifications.js';
|
import Notifications from 'resource:///com/github/Aylur/ags/service/notifications.js';
|
||||||
|
|
||||||
import { Box } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Box } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
import { interval } from 'resource:///com/github/Aylur/ags/utils.js';
|
import { interval } from 'resource:///com/github/Aylur/ags/utils.js';
|
||||||
|
|
||||||
|
@ -7,10 +8,13 @@ import GLib from 'gi://GLib';
|
||||||
import { Notification } from './base.js';
|
import { Notification } from './base.js';
|
||||||
import PopupWindow from '../misc/popup.js';
|
import PopupWindow from '../misc/popup.js';
|
||||||
|
|
||||||
|
const DELAY = 2000;
|
||||||
|
|
||||||
|
|
||||||
const addPopup = (box, id) => {
|
const addPopup = (box, id) => {
|
||||||
if (!id)
|
if (!id) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const notif = Notifications.getNotification(id);
|
const notif = Notifications.getNotification(id);
|
||||||
|
|
||||||
|
@ -20,32 +24,32 @@ const addPopup = (box, id) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (NewNotif) {
|
if (NewNotif) {
|
||||||
// use this instead of add to put it at the top
|
// Use this instead of add to put it at the top
|
||||||
box.pack_end(NewNotif, false, false, 0);
|
box.pack_end(NewNotif, false, false, 0);
|
||||||
box.show_all();
|
box.show_all();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDismiss = (box, id, force = false) => {
|
const handleDismiss = (box, id, force = false) => {
|
||||||
const notif = box.children.find(ch => ch._id === id);
|
const notif = box.children.find((ch) => ch._id === id);
|
||||||
if (!notif)
|
|
||||||
|
if (!notif) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// If notif isn't hovered or was closed, slide away
|
// If notif isn't hovered or was closed, slide away
|
||||||
if (!notif._hovered || force) {
|
if (!notif._hovered || force) {
|
||||||
notif.slideAway('Left');
|
notif.slideAway('Left');
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If notif is hovered, delay close
|
// If notif is hovered, delay close
|
||||||
else if (notif._hovered) {
|
else if (notif._hovered) {
|
||||||
notif.interval = interval(2000, () => {
|
notif.interval = interval(DELAY, () => {
|
||||||
if (!notif._hovered && notif.interval) {
|
if (!notif._hovered && notif.interval) {
|
||||||
notif.slideAway('Left');
|
notif.slideAway('Left');
|
||||||
|
|
||||||
GLib.source_remove(notif.interval);
|
GLib.source_remove(notif.interval);
|
||||||
notif.interval = undefined;
|
notif.interval = null;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -57,12 +61,14 @@ export default () => PopupWindow({
|
||||||
visible: true,
|
visible: true,
|
||||||
transition: 'none',
|
transition: 'none',
|
||||||
closeOnUnfocus: 'stay',
|
closeOnUnfocus: 'stay',
|
||||||
|
|
||||||
child: Box({
|
child: Box({
|
||||||
vertical: true,
|
vertical: true,
|
||||||
|
|
||||||
connections: [
|
connections: [
|
||||||
[Notifications, (box, id) => addPopup(box, id), 'notified'],
|
[Notifications, (s, id) => addPopup(s, id), 'notified'],
|
||||||
[Notifications, (box, id) => handleDismiss(box, id), 'dismissed'],
|
[Notifications, (s, id) => handleDismiss(s, id), 'dismissed'],
|
||||||
[Notifications, (box, id) => handleDismiss(box, id, true), 'closed'],
|
[Notifications, (s, id) => handleDismiss(s, id, true), 'closed'],
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,49 +1,60 @@
|
||||||
import { execAsync, timeout } from 'resource:///com/github/Aylur/ags/utils.js';
|
|
||||||
|
|
||||||
import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
|
import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
|
||||||
|
|
||||||
|
import { execAsync, timeout } from 'resource:///com/github/Aylur/ags/utils.js';
|
||||||
|
|
||||||
import Gtk from 'gi://Gtk';
|
import Gtk from 'gi://Gtk';
|
||||||
|
|
||||||
|
import Tablet from '../../services/tablet.js';
|
||||||
|
|
||||||
|
const KEY_N = 249;
|
||||||
|
const HIDDEN_MARGIN = 340;
|
||||||
|
const ANIM_DURATION = 700;
|
||||||
|
|
||||||
|
|
||||||
const releaseAllKeys = () => {
|
const releaseAllKeys = () => {
|
||||||
const keycodes = Array.from(Array(249).keys());
|
const keycodes = Array.from(Array(KEY_N).keys());
|
||||||
|
|
||||||
execAsync([
|
execAsync([
|
||||||
'ydotool', 'key',
|
'ydotool', 'key',
|
||||||
...keycodes.map(keycode => `${keycode}:0`),
|
...keycodes.map((keycode) => `${keycode}:0`),
|
||||||
]).catch(print);
|
]).catch(print);
|
||||||
};
|
};
|
||||||
|
|
||||||
const hidden = 340;
|
export default (window) => {
|
||||||
export default window => {
|
window.child.setCss(`margin-bottom: -${HIDDEN_MARGIN}px;`);
|
||||||
window.child.setCss(`margin-bottom: -${hidden}px;`);
|
|
||||||
const gesture = Gtk.GestureDrag.new(window);
|
const gesture = Gtk.GestureDrag.new(window);
|
||||||
|
|
||||||
window.setVisible = state => {
|
window.setVisible = (state) => {
|
||||||
if (state) {
|
if (state) {
|
||||||
window.visible = true;
|
window.visible = true;
|
||||||
window.setSlideDown();
|
window.setSlideDown();
|
||||||
window.child.setCss(`
|
window.child.setCss(`
|
||||||
transition: margin-bottom 0.7s cubic-bezier(0.36, 0, 0.66, -0.56);
|
transition: margin-bottom 0.7s
|
||||||
|
cubic-bezier(0.36, 0, 0.66, -0.56);
|
||||||
margin-bottom: 0px;
|
margin-bottom: 0px;
|
||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
timeout(710, () => {
|
timeout(ANIM_DURATION + 10, () => {
|
||||||
if (!Tablet.tabletMode)
|
if (!Tablet.tabletMode) {
|
||||||
window.visible = false;
|
window.visible = false;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
releaseAllKeys();
|
releaseAllKeys();
|
||||||
window.setSlideUp();
|
window.setSlideUp();
|
||||||
window.child.setCss(`
|
window.child.setCss(`
|
||||||
transition: margin-bottom 0.7s cubic-bezier(0.36, 0, 0.66, -0.56);
|
transition: margin-bottom 0.7s
|
||||||
margin-bottom: -${hidden}px;
|
cubic-bezier(0.36, 0, 0.66, -0.56);
|
||||||
|
margin-bottom: -${HIDDEN_MARGIN}px;
|
||||||
`);
|
`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
gesture.signals = [];
|
gesture.signals = [];
|
||||||
window.killGestureSigs = () => {
|
window.killGestureSigs = () => {
|
||||||
gesture.signals.forEach(id => gesture.disconnect(id));
|
gesture.signals.forEach((id) => {
|
||||||
|
gesture.disconnect(id);
|
||||||
|
});
|
||||||
gesture.signals = [];
|
gesture.signals = [];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -53,7 +64,7 @@ export default window => {
|
||||||
// Begin drag
|
// Begin drag
|
||||||
gesture.signals.push(
|
gesture.signals.push(
|
||||||
gesture.connect('drag-begin', () => {
|
gesture.connect('drag-begin', () => {
|
||||||
Hyprland.sendMessage('j/cursorpos').then(out => {
|
Hyprland.sendMessage('j/cursorpos').then((out) => {
|
||||||
gesture.startY = JSON.parse(out).y;
|
gesture.startY = JSON.parse(out).y;
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
@ -62,15 +73,16 @@ export default window => {
|
||||||
// Update drag
|
// Update drag
|
||||||
gesture.signals.push(
|
gesture.signals.push(
|
||||||
gesture.connect('drag-update', () => {
|
gesture.connect('drag-update', () => {
|
||||||
Hyprland.sendMessage('j/cursorpos').then(out => {
|
Hyprland.sendMessage('j/cursorpos').then((out) => {
|
||||||
const currentY = JSON.parse(out).y;
|
const currentY = JSON.parse(out).y;
|
||||||
const offset = gesture.startY - currentY;
|
const offset = gesture.startY - currentY;
|
||||||
|
|
||||||
if (offset < 0)
|
if (offset < 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
window.child.setCss(`
|
window.child.setCss(`
|
||||||
margin-bottom: ${offset - hidden}px;
|
margin-bottom: ${offset - HIDDEN_MARGIN}px;
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
@ -81,7 +93,7 @@ export default window => {
|
||||||
gesture.connect('drag-end', () => {
|
gesture.connect('drag-end', () => {
|
||||||
window.child.setCss(`
|
window.child.setCss(`
|
||||||
transition: margin-bottom 0.5s ease-in-out;
|
transition: margin-bottom 0.5s ease-in-out;
|
||||||
margin-bottom: -${hidden}px;
|
margin-bottom: -${HIDDEN_MARGIN}px;
|
||||||
`);
|
`);
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
@ -93,7 +105,7 @@ export default window => {
|
||||||
// Begin drag
|
// Begin drag
|
||||||
gesture.signals.push(
|
gesture.signals.push(
|
||||||
gesture.connect('drag-begin', () => {
|
gesture.connect('drag-begin', () => {
|
||||||
Hyprland.sendMessage('j/cursorpos').then(out => {
|
Hyprland.sendMessage('j/cursorpos').then((out) => {
|
||||||
gesture.startY = JSON.parse(out).y;
|
gesture.startY = JSON.parse(out).y;
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
@ -102,12 +114,13 @@ export default window => {
|
||||||
// Update drag
|
// Update drag
|
||||||
gesture.signals.push(
|
gesture.signals.push(
|
||||||
gesture.connect('drag-update', () => {
|
gesture.connect('drag-update', () => {
|
||||||
Hyprland.sendMessage('j/cursorpos').then(out => {
|
Hyprland.sendMessage('j/cursorpos').then((out) => {
|
||||||
const currentY = JSON.parse(out).y;
|
const currentY = JSON.parse(out).y;
|
||||||
const offset = gesture.startY - currentY;
|
const offset = gesture.startY - currentY;
|
||||||
|
|
||||||
if (offset > 0)
|
if (offset > 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
window.child.setCss(`
|
window.child.setCss(`
|
||||||
margin-bottom: ${offset}px;
|
margin-bottom: ${offset}px;
|
||||||
|
|
|
@ -8,48 +8,59 @@ import { defaultOskLayout, oskLayouts } from './keyboard-layouts.js';
|
||||||
const keyboardLayout = defaultOskLayout;
|
const keyboardLayout = defaultOskLayout;
|
||||||
const keyboardJson = oskLayouts[keyboardLayout];
|
const keyboardJson = oskLayouts[keyboardLayout];
|
||||||
|
|
||||||
const L_KEY_PER_ROW = [8, 7, 6, 6, 6, 4];
|
const L_KEY_PER_ROW = [8, 7, 6, 6, 6, 4]; // eslint-disable-line
|
||||||
|
const COLOR = 'rgba(0, 0, 0, 0.3)';
|
||||||
|
const SPACING = 4;
|
||||||
|
|
||||||
|
|
||||||
const color = 'rgba(0, 0, 0, 0.3)';
|
export default (window) => Box({
|
||||||
export default window => Box({
|
|
||||||
vertical: true,
|
vertical: true,
|
||||||
children: [
|
children: [
|
||||||
CenterBox({
|
CenterBox({
|
||||||
hpack: 'center',
|
hpack: 'center',
|
||||||
|
|
||||||
start_widget: RoundedCorner('bottomright', `
|
start_widget: RoundedCorner('bottomright', `
|
||||||
background-color: ${color};
|
background-color: ${COLOR};
|
||||||
`),
|
`),
|
||||||
|
|
||||||
center_widget: Box({
|
center_widget: Box({
|
||||||
class_name: 'thingy',
|
class_name: 'thingy',
|
||||||
css: `background: ${color};`,
|
css: `background: ${COLOR};`,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
end_widget: RoundedCorner('bottomleft', `
|
end_widget: RoundedCorner('bottomleft', `
|
||||||
background-color: ${color};
|
background-color: ${COLOR};
|
||||||
`),
|
`),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
CenterBox({
|
CenterBox({
|
||||||
css: `background: ${color};`,
|
css: `background: ${COLOR};`,
|
||||||
class_name: 'osk',
|
class_name: 'osk',
|
||||||
hexpand: true,
|
hexpand: true,
|
||||||
|
|
||||||
start_widget: Box({
|
start_widget: Box({
|
||||||
class_name: 'left-side side',
|
class_name: 'left-side side',
|
||||||
hpack: 'start',
|
hpack: 'start',
|
||||||
vertical: true,
|
vertical: true,
|
||||||
|
|
||||||
children: keyboardJson.keys.map((row, rowIndex) => Box({
|
children: keyboardJson.keys.map((row, rowIndex) => Box({
|
||||||
vertical: true,
|
vertical: true,
|
||||||
|
|
||||||
children: [
|
children: [
|
||||||
Box({
|
Box({
|
||||||
class_name: 'row',
|
class_name: 'row',
|
||||||
|
|
||||||
children: [
|
children: [
|
||||||
Separator(4),
|
Separator(SPACING),
|
||||||
...row.map((key, keyIndex) => {
|
...row.map((key, keyIndex) => {
|
||||||
return keyIndex < L_KEY_PER_ROW[rowIndex] ? Key(key) : null;
|
return keyIndex < L_KEY_PER_ROW[rowIndex] ?
|
||||||
|
Key(key) :
|
||||||
|
null;
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
Separator(4, { vertical: true }),
|
|
||||||
|
Separator(SPACING, { vertical: true }),
|
||||||
],
|
],
|
||||||
})),
|
})),
|
||||||
}),
|
}),
|
||||||
|
@ -57,19 +68,28 @@ export default window => Box({
|
||||||
center_widget: Box({
|
center_widget: Box({
|
||||||
hpack: 'center',
|
hpack: 'center',
|
||||||
vpack: 'center',
|
vpack: 'center',
|
||||||
|
|
||||||
children: [
|
children: [
|
||||||
Box({
|
Box({
|
||||||
class_name: 'settings',
|
class_name: 'settings',
|
||||||
|
|
||||||
children: [
|
children: [
|
||||||
ToggleButton({
|
ToggleButton({
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
class_name: 'button',
|
class_name: 'button',
|
||||||
active: true,
|
active: true,
|
||||||
vpack: 'center',
|
vpack: 'center',
|
||||||
connections: [['toggled', self => {
|
|
||||||
self.toggleClassName('toggled', self.get_active());
|
connections: [['toggled', (self) => {
|
||||||
window.exclusivity = self.get_active() ? 'exclusive' : 'normal';
|
self.toggleClassName(
|
||||||
|
'toggled',
|
||||||
|
self.get_active(),
|
||||||
|
);
|
||||||
|
window.exclusivity = self.get_active() ?
|
||||||
|
'exclusive' :
|
||||||
|
'normal';
|
||||||
}]],
|
}]],
|
||||||
|
|
||||||
child: Label('Exclusive'),
|
child: Label('Exclusive'),
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
@ -81,17 +101,23 @@ export default window => Box({
|
||||||
class_name: 'right-side side',
|
class_name: 'right-side side',
|
||||||
hpack: 'end',
|
hpack: 'end',
|
||||||
vertical: true,
|
vertical: true,
|
||||||
|
|
||||||
children: keyboardJson.keys.map((row, rowIndex) => Box({
|
children: keyboardJson.keys.map((row, rowIndex) => Box({
|
||||||
vertical: true,
|
vertical: true,
|
||||||
|
|
||||||
children: [
|
children: [
|
||||||
Box({
|
Box({
|
||||||
hpack: 'end',
|
hpack: 'end',
|
||||||
class_name: 'row',
|
class_name: 'row',
|
||||||
|
|
||||||
children: row.map((key, keyIndex) => {
|
children: row.map((key, keyIndex) => {
|
||||||
return keyIndex >= L_KEY_PER_ROW[rowIndex] ? Key(key) : null;
|
return keyIndex >= L_KEY_PER_ROW[rowIndex] ?
|
||||||
|
Key(key) :
|
||||||
|
null;
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
Separator(4, { vertical: true }),
|
|
||||||
|
Separator(SPACING, { vertical: true }),
|
||||||
],
|
],
|
||||||
})),
|
})),
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import Variable from 'resource:///com/github/Aylur/ags/variable.js';
|
import Variable from 'resource:///com/github/Aylur/ags/variable.js';
|
||||||
import Brightness from '../../services/brightness.js';
|
import Brightness from '../../services/brightness.js';
|
||||||
|
|
||||||
import { Box, EventBox, Label } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Box, EventBox, Label } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
import { execAsync } from 'resource:///com/github/Aylur/ags/utils.js';
|
import { execAsync } from 'resource:///com/github/Aylur/ags/utils.js';
|
||||||
|
|
||||||
|
@ -19,59 +20,73 @@ const AltGr = Variable(false);
|
||||||
const RCtrl = Variable(false);
|
const RCtrl = Variable(false);
|
||||||
|
|
||||||
const Caps = Variable(false);
|
const Caps = Variable(false);
|
||||||
Brightness.connect('caps', (_, state) => Caps.value = state);
|
|
||||||
|
Brightness.connect('caps', (_, state) => {
|
||||||
|
Caps.value = state;
|
||||||
|
});
|
||||||
|
|
||||||
// Assume both shifts are the same for key.labelShift
|
// Assume both shifts are the same for key.labelShift
|
||||||
const LShift = Variable(false);
|
const LShift = Variable(false);
|
||||||
const RShift = Variable(false);
|
const RShift = Variable(false);
|
||||||
|
|
||||||
const Shift = Variable(false);
|
const Shift = Variable(false);
|
||||||
LShift.connect('changed', () => Shift.value = LShift.value || RShift.value);
|
|
||||||
RShift.connect('changed', () => Shift.value = LShift.value || RShift.value);
|
LShift.connect('changed', () => {
|
||||||
|
Shift.value = LShift.value || RShift.value;
|
||||||
|
});
|
||||||
|
RShift.connect('changed', () => {
|
||||||
|
Shift.value = LShift.value || RShift.value;
|
||||||
|
});
|
||||||
|
|
||||||
|
const SPACING = 4;
|
||||||
|
const LSHIFT_CODE = 42;
|
||||||
|
const LALT_CODE = 56;
|
||||||
|
const LCTRL_CODE = 29;
|
||||||
|
|
||||||
|
|
||||||
export default key => {
|
const ModKey = (key) => {
|
||||||
if (key.keytype === 'normal')
|
|
||||||
return RegularKey(key);
|
|
||||||
else
|
|
||||||
return ModKey(key);
|
|
||||||
};
|
|
||||||
|
|
||||||
const ModKey = key => {
|
|
||||||
let Mod;
|
let Mod;
|
||||||
if (key.label === 'Super')
|
|
||||||
|
if (key.label === 'Super') {
|
||||||
Mod = Super;
|
Mod = Super;
|
||||||
|
}
|
||||||
|
|
||||||
// Differentiate left and right mods
|
// Differentiate left and right mods
|
||||||
else if (key.label === 'Shift' && key.keycode === 42)
|
else if (key.label === 'Shift' && key.keycode === LSHIFT_CODE) {
|
||||||
Mod = LShift;
|
Mod = LShift;
|
||||||
|
}
|
||||||
|
|
||||||
else if (key.label === 'Alt' && key.keycode === 56)
|
else if (key.label === 'Alt' && key.keycode === LALT_CODE) {
|
||||||
Mod = LAlt;
|
Mod = LAlt;
|
||||||
|
}
|
||||||
|
|
||||||
else if (key.label === 'Ctrl' && key.keycode === 29)
|
else if (key.label === 'Ctrl' && key.keycode === LCTRL_CODE) {
|
||||||
Mod = LCtrl;
|
Mod = LCtrl;
|
||||||
|
}
|
||||||
|
|
||||||
else if (key.label === 'Shift')
|
else if (key.label === 'Shift') {
|
||||||
Mod = RShift;
|
Mod = RShift;
|
||||||
|
}
|
||||||
|
|
||||||
else if (key.label === 'AltGr')
|
else if (key.label === 'AltGr') {
|
||||||
Mod = AltGr;
|
Mod = AltGr;
|
||||||
|
}
|
||||||
|
|
||||||
else if (key.label === 'Ctrl')
|
else if (key.label === 'Ctrl') {
|
||||||
Mod = RCtrl;
|
Mod = RCtrl;
|
||||||
|
}
|
||||||
|
|
||||||
const button = EventBox({
|
const button = EventBox({
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
class_name: 'key',
|
class_name: 'key',
|
||||||
onPrimaryClickRelease: self => {
|
onPrimaryClickRelease: (self) => {
|
||||||
console.log('mod toggled');
|
console.log('mod toggled');
|
||||||
|
|
||||||
execAsync(`ydotool key ${key.keycode}:${Mod.value ? 0 : 1}`);
|
execAsync(`ydotool key ${key.keycode}:${Mod.value ? 0 : 1}`);
|
||||||
self.child.toggleClassName('active', !Mod.value);
|
self.child.toggleClassName('active', !Mod.value);
|
||||||
Mod.value = !Mod.value;
|
Mod.value = !Mod.value;
|
||||||
},
|
},
|
||||||
connections: [[NormalClick, self => {
|
connections: [[NormalClick, (self) => {
|
||||||
Mod.value = false;
|
Mod.value = false;
|
||||||
self.child.toggleClassName('active', false);
|
self.child.toggleClassName('active', false);
|
||||||
execAsync(`ydotool key ${key.keycode}:0`);
|
execAsync(`ydotool key ${key.keycode}:0`);
|
||||||
|
@ -85,42 +100,49 @@ const ModKey = key => {
|
||||||
return Box({
|
return Box({
|
||||||
children: [
|
children: [
|
||||||
button,
|
button,
|
||||||
Separator(4),
|
Separator(SPACING),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const RegularKey = key => {
|
const RegularKey = (key) => {
|
||||||
const widget = EventBox({
|
const widget = EventBox({
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
class_name: 'key',
|
class_name: 'key',
|
||||||
|
|
||||||
child: Label({
|
child: Label({
|
||||||
class_name: `normal ${key.label}`,
|
class_name: `normal ${key.label}`,
|
||||||
label: key.label,
|
label: key.label,
|
||||||
|
|
||||||
connections: [
|
connections: [
|
||||||
[Shift, self => {
|
[Shift, (self) => {
|
||||||
if (!key.labelShift)
|
if (!key.labelShift) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
self.label = Shift.value ? key.labelShift : key.label;
|
self.label = Shift.value ? key.labelShift : key.label;
|
||||||
}],
|
}],
|
||||||
|
|
||||||
[Caps, self => {
|
[Caps, (self) => {
|
||||||
if (key.label === 'Caps') {
|
if (key.label === 'Caps') {
|
||||||
self.toggleClassName('active', Caps.value);
|
self.toggleClassName('active', Caps.value);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!key.labelShift)
|
if (!key.labelShift) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (key.label.match(/[A-Za-z]/))
|
if (key.label.match(/[A-Za-z]/)) {
|
||||||
self.label = Caps.value ? key.labelShift : key.label;
|
self.label = Caps.value ? key.labelShift : key.label;
|
||||||
|
}
|
||||||
}],
|
}],
|
||||||
|
|
||||||
[AltGr, self => {
|
[AltGr, (self) => {
|
||||||
if (!key.labelAltGr)
|
if (!key.labelAltGr) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
self.toggleClassName('altgr', AltGr.value);
|
self.toggleClassName('altgr', AltGr.value);
|
||||||
self.label = AltGr.value ? key.labelAltGr : key.label;
|
self.label = AltGr.value ? key.labelAltGr : key.label;
|
||||||
|
@ -130,6 +152,7 @@ const RegularKey = key => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const gesture = Gtk.GestureLongPress.new(widget);
|
const gesture = Gtk.GestureLongPress.new(widget);
|
||||||
|
|
||||||
gesture.delay_factor = 1.0;
|
gesture.delay_factor = 1.0;
|
||||||
|
|
||||||
// Long press
|
// Long press
|
||||||
|
@ -138,22 +161,24 @@ const RegularKey = key => {
|
||||||
const x = pointer[1];
|
const x = pointer[1];
|
||||||
const y = pointer[2];
|
const y = pointer[2];
|
||||||
|
|
||||||
if ((!x || !y) || x === 0 && y === 0)
|
if ((!x || !y) || (x === 0 && y === 0)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
console.log('Not implemented yet');
|
console.log('Not implemented yet');
|
||||||
|
|
||||||
// TODO: popup menu for accents
|
// TODO: popup menu for accents
|
||||||
}, 'pressed');
|
}, 'pressed');
|
||||||
|
|
||||||
// onPrimaryClickRelease
|
// OnPrimaryClickRelease
|
||||||
widget.connectTo(gesture, () => {
|
widget.connectTo(gesture, () => {
|
||||||
const pointer = gesture.get_point(null);
|
const pointer = gesture.get_point(null);
|
||||||
const x = pointer[1];
|
const x = pointer[1];
|
||||||
const y = pointer[2];
|
const y = pointer[2];
|
||||||
|
|
||||||
if ((!x || !y) || x === 0 && y === 0)
|
if ((!x || !y) || (x === 0 && y === 0)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
console.log('key clicked');
|
console.log('key clicked');
|
||||||
|
|
||||||
|
@ -165,7 +190,11 @@ const RegularKey = key => {
|
||||||
return Box({
|
return Box({
|
||||||
children: [
|
children: [
|
||||||
widget,
|
widget,
|
||||||
Separator(4),
|
Separator(SPACING),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default (key) => key.keytype === 'normal' ?
|
||||||
|
RegularKey(key) :
|
||||||
|
ModKey(key);
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
import { Window } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Window } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
import { execAsync } from 'resource:///com/github/Aylur/ags/utils.js';
|
import { execAsync } from 'resource:///com/github/Aylur/ags/utils.js';
|
||||||
|
|
||||||
|
import Tablet from '../../services/tablet.js';
|
||||||
import Gesture from './gesture.js';
|
import Gesture from './gesture.js';
|
||||||
import Keyboard from './keyboard.js';
|
import Keyboard from './keyboard.js';
|
||||||
|
|
||||||
|
|
||||||
// start ydotool daemon
|
// Start ydotool daemon
|
||||||
execAsync('ydotoold').catch(print);
|
execAsync('ydotoold').catch(print);
|
||||||
|
|
||||||
// Window
|
// Window
|
||||||
|
@ -14,17 +15,20 @@ export default () => {
|
||||||
name: 'osk',
|
name: 'osk',
|
||||||
visible: false,
|
visible: false,
|
||||||
anchor: ['left', 'bottom', 'right'],
|
anchor: ['left', 'bottom', 'right'],
|
||||||
|
|
||||||
connections: [
|
connections: [
|
||||||
[Tablet, (self, state) => {
|
[Tablet, (self, state) => {
|
||||||
self.setVisible(state);
|
self.setVisible(state);
|
||||||
}, 'osk-toggled'],
|
}, 'osk-toggled'],
|
||||||
|
|
||||||
[Tablet, () => {
|
[Tablet, () => {
|
||||||
if (!Tablet.tabletMode && !Tablet.oskState)
|
if (!Tablet.tabletMode && !Tablet.oskState) {
|
||||||
window.visible = false;
|
window.visible = false;
|
||||||
|
}
|
||||||
}, 'mode-toggled'],
|
}, 'mode-toggled'],
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
window.child = Keyboard(window);
|
window.child = Keyboard(window);
|
||||||
|
|
||||||
return Gesture(window);
|
return Gesture(window);
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
import Audio from 'resource:///com/github/Aylur/ags/service/audio.js';
|
import Audio from 'resource:///com/github/Aylur/ags/service/audio.js';
|
||||||
|
|
||||||
import { Box, Icon, ProgressBar } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Box, Icon, ProgressBar } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
|
|
||||||
import { SpeakerIcon } from '../misc/audio-icons.js';
|
import { SpeakerIcon } from '../misc/audio-icons.js';
|
||||||
|
|
||||||
|
const AUDIO_MAX = 1.5;
|
||||||
|
|
||||||
|
|
||||||
export default () => Box({
|
export default () => Box({
|
||||||
className: 'osd',
|
className: 'osd',
|
||||||
|
@ -14,14 +17,20 @@ export default () => Box({
|
||||||
|
|
||||||
ProgressBar({
|
ProgressBar({
|
||||||
vpack: 'center',
|
vpack: 'center',
|
||||||
connections: [[Audio, self => {
|
|
||||||
if (!Audio.speaker)
|
|
||||||
return;
|
|
||||||
|
|
||||||
self.value = Audio.speaker ? Audio.speaker.volume / 1.5 : 0;
|
connections: [[Audio, (self) => {
|
||||||
|
if (!Audio.speaker) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.value = Audio.speaker ?
|
||||||
|
Audio.speaker.volume / AUDIO_MAX :
|
||||||
|
0;
|
||||||
|
|
||||||
self.sensitive = !Audio.speaker?.stream.isMuted;
|
self.sensitive = !Audio.speaker?.stream.isMuted;
|
||||||
|
|
||||||
const stack = self.get_parent().get_parent();
|
const stack = self.get_parent().get_parent();
|
||||||
|
|
||||||
stack.shown = 'audio';
|
stack.shown = 'audio';
|
||||||
stack.resetTimer();
|
stack.resetTimer();
|
||||||
}, 'speaker-changed']],
|
}, 'speaker-changed']],
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import { Box, Icon, ProgressBar } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Box, Icon, ProgressBar } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
|
|
||||||
|
import Brightness from '../../services/brightness.js';
|
||||||
|
|
||||||
|
|
||||||
export default () => Box({
|
export default () => Box({
|
||||||
className: 'osd',
|
className: 'osd',
|
||||||
|
@ -11,10 +13,12 @@ export default () => Box({
|
||||||
|
|
||||||
ProgressBar({
|
ProgressBar({
|
||||||
vpack: 'center',
|
vpack: 'center',
|
||||||
connections: [[Brightness, self => {
|
|
||||||
|
connections: [[Brightness, (self) => {
|
||||||
self.value = Brightness.screen;
|
self.value = Brightness.screen;
|
||||||
|
|
||||||
const stack = self.get_parent().get_parent();
|
const stack = self.get_parent().get_parent();
|
||||||
|
|
||||||
stack.shown = 'brightness';
|
stack.shown = 'brightness';
|
||||||
stack.resetTimer();
|
stack.resetTimer();
|
||||||
}, 'screen']],
|
}, 'screen']],
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import { Box, Icon, Label } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Box, Icon, Label } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
|
|
||||||
|
import Brightness from '../../services/brightness.js';
|
||||||
|
|
||||||
|
|
||||||
export default () => Box({
|
export default () => Box({
|
||||||
className: 'osd',
|
className: 'osd',
|
||||||
|
@ -7,10 +9,14 @@ export default () => Box({
|
||||||
Icon({
|
Icon({
|
||||||
hpack: 'start',
|
hpack: 'start',
|
||||||
icon: 'caps-lock-symbolic',
|
icon: 'caps-lock-symbolic',
|
||||||
|
|
||||||
connections: [[Brightness, (self, state) => {
|
connections: [[Brightness, (self, state) => {
|
||||||
self.icon = state ? 'caps-lock-symbolic' : 'capslock-disabled-symbolic';
|
self.icon = state ?
|
||||||
|
'caps-lock-symbolic' :
|
||||||
|
'capslock-disabled-symbolic';
|
||||||
|
|
||||||
const stack = self.get_parent().get_parent();
|
const stack = self.get_parent().get_parent();
|
||||||
|
|
||||||
stack.shown = 'caps';
|
stack.shown = 'caps';
|
||||||
stack.resetTimer();
|
stack.resetTimer();
|
||||||
}, 'caps']],
|
}, 'caps']],
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
import { Box, Icon, ProgressBar } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Box, Icon, ProgressBar } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
|
|
||||||
|
import Brightness from '../../services/brightness.js';
|
||||||
|
|
||||||
|
|
||||||
export default () => Box({
|
export default () => Box({
|
||||||
className: 'osd',
|
className: 'osd',
|
||||||
|
|
||||||
children: [
|
children: [
|
||||||
Icon({
|
Icon({
|
||||||
hpack: 'start',
|
hpack: 'start',
|
||||||
|
@ -11,15 +14,18 @@ export default () => Box({
|
||||||
|
|
||||||
ProgressBar({
|
ProgressBar({
|
||||||
vpack: 'center',
|
vpack: 'center',
|
||||||
connections: [[Brightness, self => {
|
|
||||||
|
connections: [[Brightness, (self) => {
|
||||||
if (!self.value) {
|
if (!self.value) {
|
||||||
self.value = Brightness.kbd / 2;
|
self.value = Brightness.kbd / 2;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.value = Brightness.kbd / 2;
|
self.value = Brightness.kbd / 2;
|
||||||
self.sensitive = Brightness.kbd !== 0;
|
self.sensitive = Brightness.kbd !== 0;
|
||||||
|
|
||||||
const stack = self.get_parent().get_parent();
|
const stack = self.get_parent().get_parent();
|
||||||
|
|
||||||
stack.shown = 'kbd';
|
stack.shown = 'kbd';
|
||||||
stack.resetTimer();
|
stack.resetTimer();
|
||||||
}, 'kbd']],
|
}, 'kbd']],
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import App from 'resource:///com/github/Aylur/ags/app.js';
|
import App from 'resource:///com/github/Aylur/ags/app.js';
|
||||||
|
|
||||||
import { timeout } from 'resource:///com/github/Aylur/ags/utils.js';
|
import { timeout } from 'resource:///com/github/Aylur/ags/utils.js';
|
||||||
import { Stack } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Stack } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
|
|
||||||
|
@ -11,6 +12,8 @@ import CapsLock from './caps.js';
|
||||||
import Keyboard from './kbd.js';
|
import Keyboard from './kbd.js';
|
||||||
import Microphone from './mic.js';
|
import Microphone from './mic.js';
|
||||||
|
|
||||||
|
const HIDE_DELAY = 2000;
|
||||||
|
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
let setup = 0;
|
let setup = 0;
|
||||||
|
@ -37,20 +40,23 @@ export default () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
let timer;
|
let timer;
|
||||||
|
|
||||||
stack.resetTimer = () => {
|
stack.resetTimer = () => {
|
||||||
// Each osd calls resetTimer once at startup
|
// Each osd calls resetTimer once at startup
|
||||||
if (setup <= stack.items.length + 1) {
|
if (setup <= stack.items.length + 1) {
|
||||||
++setup;
|
++setup;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
App.openWindow('osd');
|
App.openWindow('osd');
|
||||||
if (timer)
|
if (timer) {
|
||||||
GLib.source_remove(timer);
|
GLib.source_remove(timer);
|
||||||
|
}
|
||||||
|
|
||||||
timer = timeout(2000, () => {
|
timer = timeout(HIDE_DELAY, () => {
|
||||||
App.closeWindow('osd');
|
App.closeWindow('osd');
|
||||||
timer = undefined;
|
timer = null;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import Audio from 'resource:///com/github/Aylur/ags/service/audio.js';
|
import Audio from 'resource:///com/github/Aylur/ags/service/audio.js';
|
||||||
|
|
||||||
import { Box, Icon, ProgressBar } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Box, Icon, ProgressBar } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
|
|
||||||
import { MicIcon } from '../misc/audio-icons.js';
|
import { MicIcon } from '../misc/audio-icons.js';
|
||||||
|
@ -6,6 +7,7 @@ import { MicIcon } from '../misc/audio-icons.js';
|
||||||
|
|
||||||
export default () => Box({
|
export default () => Box({
|
||||||
className: 'osd',
|
className: 'osd',
|
||||||
|
|
||||||
children: [
|
children: [
|
||||||
Icon({
|
Icon({
|
||||||
hpack: 'start',
|
hpack: 'start',
|
||||||
|
@ -14,14 +16,17 @@ export default () => Box({
|
||||||
|
|
||||||
ProgressBar({
|
ProgressBar({
|
||||||
vpack: 'center',
|
vpack: 'center',
|
||||||
connections: [[Audio, self => {
|
|
||||||
if (!Audio.microphone)
|
connections: [[Audio, (self) => {
|
||||||
|
if (!Audio.microphone) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
self.value = Audio.microphone ? Audio.microphone.volume : 0;
|
self.value = Audio.microphone ? Audio.microphone.volume : 0;
|
||||||
self.sensitive = !Audio.microphone?.stream.isMuted;
|
self.sensitive = !Audio.microphone?.stream.isMuted;
|
||||||
|
|
||||||
const stack = self.get_parent().get_parent();
|
const stack = self.get_parent().get_parent();
|
||||||
|
|
||||||
stack.shown = 'mic';
|
stack.shown = 'mic';
|
||||||
stack.resetTimer();
|
stack.resetTimer();
|
||||||
}, 'microphone-changed']],
|
}, 'microphone-changed']],
|
||||||
|
|
|
@ -1,21 +1,23 @@
|
||||||
import App from 'resource:///com/github/Aylur/ags/app.js';
|
import App from 'resource:///com/github/Aylur/ags/app.js';
|
||||||
import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
|
import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
|
||||||
|
|
||||||
import { Icon, Revealer } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Icon, Revealer } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
import { timeout } from 'resource:///com/github/Aylur/ags/utils.js';
|
import { timeout } from 'resource:///com/github/Aylur/ags/utils.js';
|
||||||
|
|
||||||
import { WindowButton } from './dragndrop.js';
|
import { WindowButton } from './dragndrop.js';
|
||||||
import * as VARS from './variables.js';
|
import * as VARS from './variables.js';
|
||||||
|
|
||||||
const scale = size => size * VARS.SCALE - VARS.MARGIN;
|
const scale = (size) => (size * VARS.SCALE) - VARS.MARGIN;
|
||||||
const getFontSize = client => {
|
const getFontSize = (client) => {
|
||||||
const valX = scale(client.size[0]) * VARS.ICON_SCALE;
|
const valX = scale(client.size[0]) * VARS.ICON_SCALE;
|
||||||
const valY = scale(client.size[1]) * VARS.ICON_SCALE;
|
const valY = scale(client.size[1]) * VARS.ICON_SCALE;
|
||||||
|
|
||||||
var size = Math.min(valX, valY);
|
const size = Math.min(valX, valY);
|
||||||
|
|
||||||
return size <= 0 ? 0.1 : size;
|
return size <= 0 ? 0.1 : size;
|
||||||
};
|
};
|
||||||
|
|
||||||
const IconStyle = client => `
|
const IconStyle = (client) => `
|
||||||
min-width: ${scale(client.size[0])}px;
|
min-width: ${scale(client.size[0])}px;
|
||||||
min-height: ${scale(client.size[1])}px;
|
min-height: ${scale(client.size[1])}px;
|
||||||
font-size: ${getFontSize(client)}px;
|
font-size: ${getFontSize(client)}px;
|
||||||
|
@ -29,43 +31,61 @@ const Client = (client, active, clients, box) => {
|
||||||
|
|
||||||
return Revealer({
|
return Revealer({
|
||||||
transition: 'crossfade',
|
transition: 'crossfade',
|
||||||
setup: rev => rev.revealChild = true,
|
|
||||||
|
setup: (rev) => {
|
||||||
|
rev.revealChild = true;
|
||||||
|
},
|
||||||
|
|
||||||
properties: [
|
properties: [
|
||||||
['address', client.address],
|
['address', client.address],
|
||||||
['toDestroy', false],
|
['toDestroy', false],
|
||||||
],
|
],
|
||||||
|
|
||||||
child: WindowButton({
|
child: WindowButton({
|
||||||
mainBox: box,
|
mainBox: box,
|
||||||
address: client.address,
|
address: client.address,
|
||||||
onSecondaryClickRelease: () => Hyprland.sendMessage(`dispatch closewindow ${addr}`),
|
|
||||||
|
onSecondaryClickRelease: () => {
|
||||||
|
Hyprland.sendMessage(`dispatch closewindow ${addr}`);
|
||||||
|
},
|
||||||
|
|
||||||
onPrimaryClickRelease: () => {
|
onPrimaryClickRelease: () => {
|
||||||
if (wsId < 0) {
|
if (wsId < 0) {
|
||||||
if (client.workspace.name === 'special') {
|
if (client.workspace.name === 'special') {
|
||||||
Hyprland.sendMessage(`dispatch movetoworkspacesilent special:${wsId},${addr}`)
|
Hyprland.sendMessage('dispatch ' +
|
||||||
|
`movetoworkspacesilent special:${wsId},${addr}`)
|
||||||
.then(
|
.then(
|
||||||
Hyprland.sendMessage(`dispatch togglespecialworkspace ${wsId}`)
|
Hyprland.sendMessage('dispatch ' +
|
||||||
|
`togglespecialworkspace ${wsId}`)
|
||||||
.then(
|
.then(
|
||||||
() => App.closeWindow('overview'),
|
() => App.closeWindow('overview'),
|
||||||
).catch(print),
|
).catch(print),
|
||||||
).catch(print);
|
).catch(print);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Hyprland.sendMessage(`dispatch togglespecialworkspace ${wsName}`).then(
|
Hyprland.sendMessage('dispatch ' +
|
||||||
|
`togglespecialworkspace ${wsName}`).then(
|
||||||
() => App.closeWindow('overview'),
|
() => App.closeWindow('overview'),
|
||||||
).catch(print);
|
).catch(print);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// close special workspace if one is opened
|
// Close special workspace if one is opened
|
||||||
const activeAddress = Hyprland.active.client.address;
|
const activeAddress = Hyprland.active.client.address;
|
||||||
const currentActive = clients.find(c => c.address === activeAddress);
|
|
||||||
const currentSpecial = String(currentActive.workspace.name).replace('special:', '');
|
const currentActive = clients.find((c) => {
|
||||||
|
return c.address === activeAddress;
|
||||||
|
});
|
||||||
|
|
||||||
if (currentActive && currentActive.workspace.id < 0) {
|
if (currentActive && currentActive.workspace.id < 0) {
|
||||||
Hyprland.sendMessage(`dispatch togglespecialworkspace ${currentSpecial}`)
|
const currentSpecial = `${currentActive.workspace.name}`
|
||||||
|
.replace('special:', '');
|
||||||
|
|
||||||
|
Hyprland.sendMessage('dispatch ' +
|
||||||
|
`togglespecialworkspace ${currentSpecial}`)
|
||||||
.catch(print);
|
.catch(print);
|
||||||
}
|
}
|
||||||
|
|
||||||
Hyprland.sendMessage(`dispatch focuswindow ${addr}`).then(
|
Hyprland.sendMessage(`dispatch focuswindow ${addr}`).then(
|
||||||
() => App.closeWindow('overview'),
|
() => App.closeWindow('overview'),
|
||||||
).catch(print);
|
).catch(print);
|
||||||
|
@ -74,26 +94,28 @@ const Client = (client, active, clients, box) => {
|
||||||
|
|
||||||
child: Icon({
|
child: Icon({
|
||||||
className: `window ${active}`,
|
className: `window ${active}`,
|
||||||
css: IconStyle(client) + 'font-size: 10px;',
|
css: `${IconStyle(client) }font-size: 10px;`,
|
||||||
icon: client.class,
|
icon: client.class,
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export function updateClients(box) {
|
export const updateClients = (box) => {
|
||||||
Hyprland.sendMessage('j/clients').then(out => {
|
Hyprland.sendMessage('j/clients').then((out) => {
|
||||||
const clients = JSON.parse(out).filter(client => client.class);
|
const clients = JSON.parse(out).filter((client) => client.class);
|
||||||
|
|
||||||
box._workspaces.forEach(workspace => {
|
box._workspaces.forEach((workspace) => {
|
||||||
const fixed = workspace.getFixed();
|
const fixed = workspace.getFixed();
|
||||||
const toRemove = fixed.get_children();
|
const toRemove = fixed.get_children();
|
||||||
|
|
||||||
clients.filter(client => client.workspace.id == workspace._id)
|
clients.filter((client) => client.workspace.id === workspace._id)
|
||||||
.forEach(client => {
|
.forEach((client) => {
|
||||||
let active = '';
|
let active = '';
|
||||||
if (client.address == Hyprland.active.client.address)
|
|
||||||
|
if (client.address === Hyprland.active.client.address) {
|
||||||
active = 'active';
|
active = 'active';
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: fix multi monitor issue. this is just a temp fix
|
// TODO: fix multi monitor issue. this is just a temp fix
|
||||||
client.at[1] -= 2920;
|
client.at[1] -= 2920;
|
||||||
|
@ -109,19 +131,21 @@ export function updateClients(box) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const newClient = [
|
const newClient = [
|
||||||
fixed.get_children().find(ch => ch._address == client.address),
|
fixed.get_children()
|
||||||
|
.find((ch) => ch._address === client.address),
|
||||||
client.at[0] * VARS.SCALE,
|
client.at[0] * VARS.SCALE,
|
||||||
client.at[1] * VARS.SCALE,
|
client.at[1] * VARS.SCALE,
|
||||||
];
|
];
|
||||||
|
|
||||||
if (!newClient[0]) {
|
// If it exists already
|
||||||
newClient[0] = Client(client, active, clients, box);
|
if (newClient[0]) {
|
||||||
fixed.put(...newClient);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
toRemove.splice(toRemove.indexOf(newClient[0]), 1);
|
toRemove.splice(toRemove.indexOf(newClient[0]), 1);
|
||||||
fixed.move(...newClient);
|
fixed.move(...newClient);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
newClient[0] = Client(client, active, clients, box);
|
||||||
|
fixed.put(...newClient);
|
||||||
|
}
|
||||||
|
|
||||||
// Set a timeout here to have an animation when the icon first appears
|
// Set a timeout here to have an animation when the icon first appears
|
||||||
timeout(1, () => {
|
timeout(1, () => {
|
||||||
|
@ -131,7 +155,7 @@ export function updateClients(box) {
|
||||||
});
|
});
|
||||||
|
|
||||||
fixed.show_all();
|
fixed.show_all();
|
||||||
toRemove.forEach(ch => {
|
toRemove.forEach((ch) => {
|
||||||
if (ch._toDestroy) {
|
if (ch._toDestroy) {
|
||||||
ch.destroy();
|
ch.destroy();
|
||||||
}
|
}
|
||||||
|
@ -142,4 +166,4 @@ export function updateClients(box) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}).catch(print);
|
}).catch(print);
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
|
import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
|
||||||
|
|
||||||
import { Box } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Box } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
import * as VARS from './variables.js';
|
import * as VARS from './variables.js';
|
||||||
|
|
||||||
|
const PADDING = 34;
|
||||||
|
const MARGIN = 9;
|
||||||
const DEFAULT_STYLE = `
|
const DEFAULT_STYLE = `
|
||||||
min-width: ${VARS.SCREEN.X * VARS.SCALE}px;
|
min-width: ${VARS.SCREEN.X * VARS.SCALE}px;
|
||||||
min-height: ${VARS.SCREEN.Y * VARS.SCALE - 4}px;
|
min-height: ${(VARS.SCREEN.Y * VARS.SCALE) - (VARS.MARGIN / 2)}px;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
@ -21,14 +24,16 @@ export const updateCurrentWorkspace = (main, highlighter) => {
|
||||||
const row = Math.floor((currentId - 1) / VARS.WORKSPACE_PER_ROW);
|
const row = Math.floor((currentId - 1) / VARS.WORKSPACE_PER_ROW);
|
||||||
|
|
||||||
const rowObject = main.children[0].children[row];
|
const rowObject = main.children[0].children[row];
|
||||||
const workspaces = rowObject.child.centerWidget.child.get_children().filter(w => w.revealChild);
|
const workspaces = rowObject.child.centerWidget.child
|
||||||
|
.get_children().filter((w) => w.revealChild);
|
||||||
|
|
||||||
const height = row * (VARS.SCREEN.Y * VARS.SCALE + 17);
|
const currentIndex = workspaces.findIndex((w) => w._id === currentId);
|
||||||
const currentIndex = workspaces.findIndex(w => w._id == currentId);
|
const left = currentIndex * ((VARS.SCREEN.X * VARS.SCALE) + PADDING);
|
||||||
|
const height = row * ((VARS.SCREEN.Y * VARS.SCALE) + (PADDING / 2));
|
||||||
|
|
||||||
highlighter.setCss(`
|
highlighter.setCss(`
|
||||||
${DEFAULT_STYLE}
|
${DEFAULT_STYLE}
|
||||||
margin-left: ${9 + currentIndex * (VARS.SCREEN.X * VARS.SCALE + 34)}px;
|
margin-left: ${MARGIN + left}px;
|
||||||
margin-top: ${9 + height}px;
|
margin-top: ${MARGIN + height}px;
|
||||||
`);
|
`);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
|
import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
|
||||||
|
|
||||||
import { EventBox } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { EventBox } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
|
|
||||||
import Gtk from 'gi://Gtk';
|
import Gtk from 'gi://Gtk';
|
||||||
|
@ -11,7 +12,7 @@ import { updateClients } from './clients.js';
|
||||||
const TARGET = [Gtk.TargetEntry.new('text/plain', Gtk.TargetFlags.SAME_APP, 0)];
|
const TARGET = [Gtk.TargetEntry.new('text/plain', Gtk.TargetFlags.SAME_APP, 0)];
|
||||||
|
|
||||||
|
|
||||||
function createSurfaceFromWidget(widget) {
|
const createSurfaceFromWidget = (widget) => {
|
||||||
const alloc = widget.get_allocation();
|
const alloc = widget.get_allocation();
|
||||||
const surface = new Cairo.ImageSurface(
|
const surface = new Cairo.ImageSurface(
|
||||||
Cairo.Format.ARGB32,
|
Cairo.Format.ARGB32,
|
||||||
|
@ -19,33 +20,40 @@ function createSurfaceFromWidget(widget) {
|
||||||
alloc.height,
|
alloc.height,
|
||||||
);
|
);
|
||||||
const cr = new Cairo.Context(surface);
|
const cr = new Cairo.Context(surface);
|
||||||
|
|
||||||
cr.setSourceRGBA(255, 255, 255, 0);
|
cr.setSourceRGBA(255, 255, 255, 0);
|
||||||
cr.rectangle(0, 0, alloc.width, alloc.height);
|
cr.rectangle(0, 0, alloc.width, alloc.height);
|
||||||
cr.fill();
|
cr.fill();
|
||||||
widget.draw(cr);
|
widget.draw(cr);
|
||||||
|
|
||||||
return surface;
|
return surface;
|
||||||
}
|
};
|
||||||
|
|
||||||
let hidden = 0;
|
let hidden = 0;
|
||||||
export const WorkspaceDrop = props => EventBox({
|
|
||||||
|
export const WorkspaceDrop = (props) => EventBox({
|
||||||
...props,
|
...props,
|
||||||
connections: [['drag-data-received', (self, _c, _x, _y, data) => {
|
connections: [['drag-data-received', (self, _c, _x, _y, data) => {
|
||||||
let id = self.get_parent()._id;
|
let id = self.get_parent()._id;
|
||||||
|
|
||||||
if (id < -1)
|
if (id < -1) {
|
||||||
id = self.get_parent()._name;
|
id = self.get_parent()._name;
|
||||||
|
}
|
||||||
|
|
||||||
else if (id === -1)
|
else if (id === -1) {
|
||||||
id = `special:${++hidden}`;
|
id = `special:${++hidden}`;
|
||||||
|
}
|
||||||
|
|
||||||
else if (id === 1000)
|
else if (id === 1000) {
|
||||||
id = 'empty';
|
id = 'empty';
|
||||||
|
}
|
||||||
|
|
||||||
Hyprland.sendMessage(`dispatch movetoworkspacesilent ${id},address:${data.get_text()}`)
|
Hyprland.sendMessage('dispatch ' +
|
||||||
|
`movetoworkspacesilent ${id},address:${data.get_text()}`)
|
||||||
.catch(print);
|
.catch(print);
|
||||||
}]],
|
}]],
|
||||||
setup: self => {
|
|
||||||
|
setup: (self) => {
|
||||||
self.drag_dest_set(Gtk.DestDefaults.ALL, TARGET, Gdk.DragAction.COPY);
|
self.drag_dest_set(Gtk.DestDefaults.ALL, TARGET, Gdk.DragAction.COPY);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -53,15 +61,23 @@ export const WorkspaceDrop = props => EventBox({
|
||||||
export const WindowButton = ({ address, mainBox, ...props } = {}) => Button({
|
export const WindowButton = ({ address, mainBox, ...props } = {}) => Button({
|
||||||
isButton: true,
|
isButton: true,
|
||||||
...props,
|
...props,
|
||||||
setup: self => {
|
|
||||||
self.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, TARGET, Gdk.DragAction.COPY);
|
setup: (self) => {
|
||||||
|
self.drag_source_set(
|
||||||
|
Gdk.ModifierType.BUTTON1_MASK,
|
||||||
|
TARGET,
|
||||||
|
Gdk.DragAction.COPY,
|
||||||
|
);
|
||||||
|
|
||||||
self.connect('drag-data-get', (_w, _c, data) => {
|
self.connect('drag-data-get', (_w, _c, data) => {
|
||||||
data.set_text(address, address.length);
|
data.set_text(address, address.length);
|
||||||
});
|
});
|
||||||
|
|
||||||
self.connect('drag-begin', (_, context) => {
|
self.connect('drag-begin', (_, context) => {
|
||||||
Gtk.drag_set_icon_surface(context, createSurfaceFromWidget(self));
|
Gtk.drag_set_icon_surface(context, createSurfaceFromWidget(self));
|
||||||
self.get_parent().revealChild = false;
|
self.get_parent().revealChild = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
self.connect('drag-end', () => {
|
self.connect('drag-end', () => {
|
||||||
self.get_parent().destroy();
|
self.get_parent().destroy();
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import App from 'resource:///com/github/Aylur/ags/app.js';
|
import App from 'resource:///com/github/Aylur/ags/app.js';
|
||||||
import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
|
import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
|
||||||
|
|
||||||
import { Box, Overlay } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Box, Overlay } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
|
|
||||||
import PopupWindow from '../misc/popup.js';
|
import PopupWindow from '../misc/popup.js';
|
||||||
|
@ -8,25 +9,26 @@ import { Highlighter, updateCurrentWorkspace } from './current-workspace.js';
|
||||||
import { updateClients } from './clients.js';
|
import { updateClients } from './clients.js';
|
||||||
|
|
||||||
|
|
||||||
function update(box, highlight) {
|
const update = (box, highlight) => {
|
||||||
getWorkspaces(box);
|
getWorkspaces(box);
|
||||||
updateWorkspaces(box);
|
updateWorkspaces(box);
|
||||||
updateClients(box);
|
updateClients(box);
|
||||||
updateCurrentWorkspace(box, highlight);
|
updateCurrentWorkspace(box, highlight);
|
||||||
}
|
};
|
||||||
|
|
||||||
// TODO: have a 'page' for each monitor, arrows on both sides to loop through
|
// TODO: have a 'page' for each monitor, arrows on both sides to loop through
|
||||||
export default () => {
|
export default () => {
|
||||||
const highlighter = Highlighter();
|
const highlighter = Highlighter();
|
||||||
|
|
||||||
const mainBox = Box({
|
const mainBox = Box({
|
||||||
// do this for scss hierarchy
|
// Do this for scss hierarchy
|
||||||
className: 'overview',
|
className: 'overview',
|
||||||
css: 'all: unset',
|
css: 'all: unset',
|
||||||
|
|
||||||
vertical: true,
|
vertical: true,
|
||||||
vpack: 'center',
|
vpack: 'center',
|
||||||
hpack: 'center',
|
hpack: 'center',
|
||||||
|
|
||||||
children: [
|
children: [
|
||||||
Box({
|
Box({
|
||||||
vertical: true,
|
vertical: true,
|
||||||
|
@ -34,6 +36,7 @@ export default () => {
|
||||||
WorkspaceRow('normal', 0),
|
WorkspaceRow('normal', 0),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Box({
|
Box({
|
||||||
vertical: true,
|
vertical: true,
|
||||||
children: [
|
children: [
|
||||||
|
@ -41,12 +44,15 @@ export default () => {
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
connections: [[Hyprland, self => {
|
|
||||||
if (!App.getWindow('overview').visible)
|
connections: [[Hyprland, (self) => {
|
||||||
|
if (!App.getWindow('overview').visible) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
update(self, highlighter);
|
update(self, highlighter);
|
||||||
}]],
|
}]],
|
||||||
|
|
||||||
properties: [
|
properties: [
|
||||||
['workspaces'],
|
['workspaces'],
|
||||||
],
|
],
|
||||||
|
@ -67,6 +73,7 @@ export default () => {
|
||||||
min-width: ${mainBox.get_allocated_width()}px;
|
min-width: ${mainBox.get_allocated_width()}px;
|
||||||
`,
|
`,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
// TODO: throttle his?
|
// TODO: throttle his?
|
||||||
connections: [['get-child-position', (self, ch) => {
|
connections: [['get-child-position', (self, ch) => {
|
||||||
if (ch === mainBox) {
|
if (ch === mainBox) {
|
||||||
|
@ -80,5 +87,6 @@ export default () => {
|
||||||
}),
|
}),
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return window;
|
return window;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,91 +1,65 @@
|
||||||
import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
|
import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
|
||||||
|
|
||||||
import { Revealer, CenterBox, Box, EventBox, Fixed, Label } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Revealer, CenterBox, Box, EventBox, Fixed, Label } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
|
|
||||||
import { WorkspaceDrop } from './dragndrop.js';
|
import { WorkspaceDrop } from './dragndrop.js';
|
||||||
import * as VARS from './variables.js';
|
import * as VARS from './variables.js';
|
||||||
|
|
||||||
const DEFAULT_STYLE = `min-width: ${VARS.SCREEN.X * VARS.SCALE}px;
|
const DEFAULT_STYLE = `
|
||||||
min-height: ${VARS.SCREEN.Y * VARS.SCALE}px;`;
|
min-width: ${VARS.SCREEN.X * VARS.SCALE}px;
|
||||||
|
min-height: ${VARS.SCREEN.Y * VARS.SCALE}px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
|
||||||
export function getWorkspaces(box) {
|
export const getWorkspaces = (box) => {
|
||||||
const children = [];
|
const children = [];
|
||||||
box.children.forEach(type => {
|
|
||||||
type.children.forEach(row => {
|
box.children.forEach((type) => {
|
||||||
row.child.centerWidget.child.children.forEach(ch => {
|
type.children.forEach((row) => {
|
||||||
|
row.child.centerWidget.child.children.forEach((ch) => {
|
||||||
children.push(ch);
|
children.push(ch);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
box._workspaces = children.sort((a, b) => a._id - b._id);
|
box._workspaces = children.sort((a, b) => a._id - b._id);
|
||||||
}
|
};
|
||||||
|
|
||||||
export const WorkspaceRow = (className, i) => Revealer({
|
const Workspace = (id, name, normal = true) => {
|
||||||
transition: 'slide_down',
|
|
||||||
hpack: className === 'special' ? '' : 'start',
|
|
||||||
connections: [[Hyprland, rev => {
|
|
||||||
const minId = i * VARS.WORKSPACE_PER_ROW;
|
|
||||||
const activeId = Hyprland.active.workspace.id;
|
|
||||||
|
|
||||||
rev.revealChild = Hyprland.workspaces
|
|
||||||
.some(ws => ws.id > minId &&
|
|
||||||
(ws.windows > 0 || ws.id === activeId));
|
|
||||||
}]],
|
|
||||||
child: CenterBox({
|
|
||||||
children: [null, EventBox({
|
|
||||||
connections: [[Hyprland, eventbox => {
|
|
||||||
const maxId = i * VARS.WORKSPACE_PER_ROW + VARS.WORKSPACE_PER_ROW;
|
|
||||||
const activeId = Hyprland.active.workspace.id;
|
|
||||||
|
|
||||||
eventbox.child.children[0].revealChild = className === 'special' ||
|
|
||||||
!Hyprland.workspaces.some(ws => ws.id > maxId &&
|
|
||||||
(ws.windows > 0 || ws.id === activeId));
|
|
||||||
}]],
|
|
||||||
child: Box({
|
|
||||||
className: className,
|
|
||||||
children: [
|
|
||||||
// the 'add' workspace
|
|
||||||
Workspace(className === 'special' ? -1 : 1000,
|
|
||||||
className === 'special' ? 'special' : '',
|
|
||||||
true),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
}), null],
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
const Workspace = (id, name, extra = false) => {
|
|
||||||
let workspace;
|
|
||||||
const fixed = Fixed();
|
const fixed = Fixed();
|
||||||
|
|
||||||
if (!extra) {
|
const workspace = Revealer({
|
||||||
workspace = Revealer({
|
|
||||||
transition: 'slide_right',
|
transition: 'slide_right',
|
||||||
transitionDuration: 500,
|
transitionDuration: 500,
|
||||||
connections: [[Hyprland, box => {
|
|
||||||
|
connections: normal ?
|
||||||
|
|
||||||
|
[[Hyprland, (box) => {
|
||||||
const activeId = Hyprland.active.workspace.id;
|
const activeId = Hyprland.active.workspace.id;
|
||||||
const active = activeId === box._id;
|
const active = activeId === box._id;
|
||||||
|
|
||||||
box.revealChild = Hyprland.getWorkspace(box._id)?.windows > 0 || active;
|
box.revealChild = Hyprland.getWorkspace(box._id)
|
||||||
}]],
|
?.windows > 0 || active;
|
||||||
|
}]] :
|
||||||
|
|
||||||
|
[],
|
||||||
|
|
||||||
child: WorkspaceDrop({
|
child: WorkspaceDrop({
|
||||||
child: Box({
|
child: Box({
|
||||||
className: 'workspace',
|
className: 'workspace',
|
||||||
css: DEFAULT_STYLE,
|
css: normal ?
|
||||||
child: fixed,
|
|
||||||
}),
|
DEFAULT_STYLE :
|
||||||
}),
|
|
||||||
});
|
`
|
||||||
}
|
min-width: ${VARS.SCREEN.X * VARS.SCALE / 2}px;
|
||||||
// 'add' workspace
|
min-height: ${VARS.SCREEN.Y * VARS.SCALE}px;
|
||||||
else {
|
`,
|
||||||
workspace = Revealer({
|
|
||||||
transition: 'slide_right',
|
children: normal ?
|
||||||
child: WorkspaceDrop({
|
|
||||||
child: Box({
|
[fixed] :
|
||||||
css: `min-width: ${VARS.SCREEN.X * VARS.SCALE / 2}px;
|
|
||||||
min-height: ${VARS.SCREEN.Y * VARS.SCALE}px;`,
|
[
|
||||||
children: [
|
|
||||||
fixed,
|
fixed,
|
||||||
Label({
|
Label({
|
||||||
label: ' +',
|
label: ' +',
|
||||||
|
@ -95,20 +69,74 @@ const Workspace = (id, name, extra = false) => {
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
workspace._id = id;
|
workspace._id = id;
|
||||||
workspace._name = name;
|
workspace._name = name;
|
||||||
workspace.getFixed = () => fixed;
|
workspace.getFixed = () => fixed;
|
||||||
|
|
||||||
return workspace;
|
return workspace;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function updateWorkspaces(box) {
|
export const WorkspaceRow = (className, i) => {
|
||||||
Hyprland.workspaces.forEach(ws => {
|
const addWorkspace = Workspace(
|
||||||
const currentWs = box._workspaces.find(ch => ch._id == ws.id);
|
className === 'special' ? -1 : 1000,
|
||||||
|
className === 'special' ? 'special' : '',
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
|
return Revealer({
|
||||||
|
transition: 'slide_down',
|
||||||
|
hpack: className === 'special' ? '' : 'start',
|
||||||
|
|
||||||
|
connections: [[Hyprland, (rev) => {
|
||||||
|
const minId = i * VARS.WORKSPACE_PER_ROW;
|
||||||
|
const activeId = Hyprland.active.workspace.id;
|
||||||
|
|
||||||
|
const rowExists = Hyprland.workspaces.some((ws) => {
|
||||||
|
const isInRow = ws.id > minId;
|
||||||
|
const hasClients = ws.windows > 0;
|
||||||
|
const isActive = ws.id === activeId;
|
||||||
|
|
||||||
|
return isInRow && (hasClients || isActive);
|
||||||
|
});
|
||||||
|
|
||||||
|
rev.revealChild = rowExists;
|
||||||
|
}]],
|
||||||
|
|
||||||
|
child: CenterBox({
|
||||||
|
children: [null, EventBox({
|
||||||
|
connections: [[Hyprland, () => {
|
||||||
|
const maxId = (i + 1) * VARS.WORKSPACE_PER_ROW;
|
||||||
|
const activeId = Hyprland.active.workspace.id;
|
||||||
|
|
||||||
|
const isSpecial = className === 'special';
|
||||||
|
const nextRowExists = Hyprland.workspaces.some((ws) => {
|
||||||
|
const isInNextRow = ws.id > maxId;
|
||||||
|
const hasClients = ws.windows > 0;
|
||||||
|
const isActive = ws.id === activeId;
|
||||||
|
|
||||||
|
return isInNextRow && (hasClients || isActive);
|
||||||
|
});
|
||||||
|
|
||||||
|
addWorkspace.revealChild = isSpecial || !nextRowExists;
|
||||||
|
}]],
|
||||||
|
|
||||||
|
child: Box({
|
||||||
|
className,
|
||||||
|
children: [addWorkspace],
|
||||||
|
}),
|
||||||
|
}), null],
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const updateWorkspaces = (box) => {
|
||||||
|
Hyprland.workspaces.forEach((ws) => {
|
||||||
|
const currentWs = box._workspaces.find((ch) => ch._id === ws.id);
|
||||||
|
|
||||||
if (!currentWs) {
|
if (!currentWs) {
|
||||||
var type = 0;
|
let type = 0;
|
||||||
var rowNo = 0;
|
let rowNo = 0;
|
||||||
|
|
||||||
if (ws.id < 0) {
|
if (ws.id < 0) {
|
||||||
// This means it's a special workspace
|
// This means it's a special workspace
|
||||||
|
@ -116,12 +144,19 @@ export function updateWorkspaces(box) {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
rowNo = Math.floor((ws.id - 1) / VARS.WORKSPACE_PER_ROW);
|
rowNo = Math.floor((ws.id - 1) / VARS.WORKSPACE_PER_ROW);
|
||||||
if (rowNo >= box.children[type].children.length) {
|
const wsQty = box.children[type].children.length;
|
||||||
for (let i = box.children[type].children.length; i <= rowNo; ++i)
|
|
||||||
box.children[type].add(WorkspaceRow(type ? 'special' : 'normal', i));
|
if (rowNo >= wsQty) {
|
||||||
|
for (let i = wsQty; i <= rowNo; ++i) {
|
||||||
|
box.children[type].add(WorkspaceRow(
|
||||||
|
type ? 'special' : 'normal', i,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var row = box.children[type].children[rowNo].child.centerWidget.child;
|
}
|
||||||
|
const row = box.children[type].children[rowNo]
|
||||||
|
.child.centerWidget.child;
|
||||||
|
|
||||||
row.add(Workspace(ws.id, type ? ws.name : ''));
|
row.add(Workspace(ws.id, type ? ws.name : ''));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -131,4 +166,4 @@ export function updateWorkspaces(box) {
|
||||||
workspace.get_parent().reorder_child(workspace, i);
|
workspace.get_parent().reorder_child(workspace, i);
|
||||||
});
|
});
|
||||||
box.show_all();
|
box.show_all();
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
|
import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
|
||||||
|
|
||||||
import { CenterBox, Label } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { CenterBox, Label } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
import { execAsync } from 'resource:///com/github/Aylur/ags/utils.js';
|
import { execAsync } from 'resource:///com/github/Aylur/ags/utils.js';
|
||||||
|
|
||||||
|
@ -13,7 +14,8 @@ const PowermenuWidget = () => CenterBox({
|
||||||
startWidget: Button({
|
startWidget: Button({
|
||||||
isButton: true,
|
isButton: true,
|
||||||
className: 'shutdown',
|
className: 'shutdown',
|
||||||
onPrimaryClickRelease: () => execAsync(['systemctl', 'poweroff']).catch(print),
|
onPrimaryClickRelease: () => execAsync(['systemctl', 'poweroff'])
|
||||||
|
.catch(print),
|
||||||
|
|
||||||
child: Label({
|
child: Label({
|
||||||
label: '襤',
|
label: '襤',
|
||||||
|
@ -23,7 +25,8 @@ const PowermenuWidget = () => CenterBox({
|
||||||
centerWidget: Button({
|
centerWidget: Button({
|
||||||
isButton: true,
|
isButton: true,
|
||||||
className: 'reboot',
|
className: 'reboot',
|
||||||
onPrimaryClickRelease: () => execAsync(['systemctl', 'reboot']).catch(print),
|
onPrimaryClickRelease: () => execAsync(['systemctl', 'reboot'])
|
||||||
|
.catch(print),
|
||||||
|
|
||||||
child: Label({
|
child: Label({
|
||||||
label: '勒',
|
label: '勒',
|
||||||
|
@ -33,7 +36,8 @@ const PowermenuWidget = () => CenterBox({
|
||||||
endWidget: Button({
|
endWidget: Button({
|
||||||
isButton: true,
|
isButton: true,
|
||||||
className: 'logout',
|
className: 'logout',
|
||||||
onPrimaryClickRelease: () => Hyprland.sendMessage('dispatch exit').catch(print),
|
onPrimaryClickRelease: () => Hyprland.sendMessage('dispatch exit')
|
||||||
|
.catch(print),
|
||||||
|
|
||||||
child: Label({
|
child: Label({
|
||||||
label: '',
|
label: '',
|
||||||
|
|
|
@ -2,6 +2,7 @@ import App from 'resource:///com/github/Aylur/ags/app.js';
|
||||||
import Bluetooth from 'resource:///com/github/Aylur/ags/service/bluetooth.js';
|
import Bluetooth from 'resource:///com/github/Aylur/ags/service/bluetooth.js';
|
||||||
import Network from 'resource:///com/github/Aylur/ags/service/network.js';
|
import Network from 'resource:///com/github/Aylur/ags/service/network.js';
|
||||||
import Variable from 'resource:///com/github/Aylur/ags/variable.js';
|
import Variable from 'resource:///com/github/Aylur/ags/variable.js';
|
||||||
|
|
||||||
import { Box, Icon, Label, Revealer } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Box, Icon, Label, Revealer } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
import { execAsync } from 'resource:///com/github/Aylur/ags/utils.js';
|
import { execAsync } from 'resource:///com/github/Aylur/ags/utils.js';
|
||||||
|
|
||||||
|
@ -9,25 +10,30 @@ import { SpeakerIcon, MicIcon } from '../misc/audio-icons.js';
|
||||||
import EventBox from '../misc/cursorbox.js';
|
import EventBox from '../misc/cursorbox.js';
|
||||||
import Separator from '../misc/separator.js';
|
import Separator from '../misc/separator.js';
|
||||||
|
|
||||||
|
const SPACING = 28;
|
||||||
|
|
||||||
|
|
||||||
const ButtonStates = [];
|
const ButtonStates = [];
|
||||||
const GridButton = ({
|
const GridButton = ({
|
||||||
command = () => {},
|
command = () => { /**/ },
|
||||||
secondaryCommand = () => {},
|
secondaryCommand = () => { /**/ },
|
||||||
icon,
|
icon,
|
||||||
indicator,
|
indicator,
|
||||||
menu,
|
menu,
|
||||||
} = {}) => {
|
} = {}) => {
|
||||||
const Activated = Variable(false);
|
const Activated = Variable(false);
|
||||||
|
|
||||||
ButtonStates.push(Activated);
|
ButtonStates.push(Activated);
|
||||||
|
|
||||||
// allow setting icon dynamically or statically
|
// Allow setting icon dynamically or statically
|
||||||
if (typeof icon === 'string') {
|
if (typeof icon === 'string') {
|
||||||
icon = Icon({
|
icon = Icon({
|
||||||
className: 'grid-label',
|
className: 'grid-label',
|
||||||
icon: icon,
|
icon,
|
||||||
connections: [[Activated, self => {
|
connections: [[Activated, (self) => {
|
||||||
self.setCss(`color: ${Activated.value ? 'rgba(189, 147, 249, 0.8)' : 'unset'};`);
|
self.setCss(`color: ${Activated.value ?
|
||||||
|
'rgba(189, 147, 249, 0.8)' :
|
||||||
|
'unset'};`);
|
||||||
}]],
|
}]],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -36,8 +42,10 @@ const GridButton = ({
|
||||||
className: 'grid-label',
|
className: 'grid-label',
|
||||||
connections: [
|
connections: [
|
||||||
icon,
|
icon,
|
||||||
[Activated, self => {
|
[Activated, (self) => {
|
||||||
self.setCss(`color: ${Activated.value ? 'rgba(189, 147, 249, 0.8)' : 'unset'};`);
|
self.setCss(`color: ${Activated.value ?
|
||||||
|
'rgba(189, 147, 249, 0.8)' :
|
||||||
|
'unset'};`);
|
||||||
}],
|
}],
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
@ -70,44 +78,60 @@ const GridButton = ({
|
||||||
|
|
||||||
EventBox({
|
EventBox({
|
||||||
className: 'left-part',
|
className: 'left-part',
|
||||||
|
|
||||||
onPrimaryClickRelease: () => {
|
onPrimaryClickRelease: () => {
|
||||||
if (!Activated.value)
|
if (Activated.value) {
|
||||||
command();
|
|
||||||
else
|
|
||||||
secondaryCommand();
|
secondaryCommand();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
command();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
child: icon,
|
child: icon,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
EventBox({
|
EventBox({
|
||||||
className: 'right-part',
|
className: 'right-part',
|
||||||
|
|
||||||
onPrimaryClickRelease: () => {
|
onPrimaryClickRelease: () => {
|
||||||
ButtonStates.forEach(state => {
|
ButtonStates.forEach((state) => {
|
||||||
if (state !== Activated)
|
if (state !== Activated) {
|
||||||
state.value = false;
|
state.value = false;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
Activated.value = !Activated.value;
|
Activated.value = !Activated.value;
|
||||||
},
|
},
|
||||||
onHover: self => {
|
|
||||||
|
onHover: (self) => {
|
||||||
if (menu) {
|
if (menu) {
|
||||||
const rowMenu = self.get_parent().get_parent()
|
const rowMenu = self.get_parent().get_parent()
|
||||||
.get_parent().get_parent().children[1];
|
.get_parent().get_parent().children[1];
|
||||||
|
|
||||||
if (!rowMenu.get_children().find(ch => ch === menu)) {
|
const isSetup = rowMenu.get_children()
|
||||||
|
.find((ch) => ch === menu);
|
||||||
|
|
||||||
|
if (!isSetup) {
|
||||||
rowMenu.add(menu);
|
rowMenu.add(menu);
|
||||||
rowMenu.show_all();
|
rowMenu.show_all();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
child: Icon({
|
child: Icon({
|
||||||
icon: App.configDir + '/icons/down-large.svg',
|
icon: `${App.configDir }/icons/down-large.svg`,
|
||||||
connections: [[Activated, self => {
|
|
||||||
let deg = 270;
|
|
||||||
if (Activated.value)
|
|
||||||
deg = menu ? 360 : 450;
|
|
||||||
self.setCss(`-gtk-icon-transform: rotate(${deg}deg);`);
|
|
||||||
}]],
|
|
||||||
className: 'grid-chev',
|
className: 'grid-chev',
|
||||||
|
|
||||||
|
connections: [[Activated, (self) => {
|
||||||
|
let deg = 270;
|
||||||
|
|
||||||
|
if (Activated.value) {
|
||||||
|
deg = menu ? 360 : 450;
|
||||||
|
}
|
||||||
|
self.setCss(`
|
||||||
|
-gtk-icon-transform: rotate(${deg}deg);
|
||||||
|
`);
|
||||||
|
}]],
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
@ -116,30 +140,34 @@ const GridButton = ({
|
||||||
indicator,
|
indicator,
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
return widget;
|
return widget;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Row = ({ buttons } = {}) => {
|
const Row = ({ buttons } = {}) => {
|
||||||
const widget = Box({
|
const widget = Box({
|
||||||
vertical: true,
|
vertical: true,
|
||||||
|
|
||||||
children: [
|
children: [
|
||||||
Box({
|
Box({
|
||||||
className: 'button-row',
|
className: 'button-row',
|
||||||
hpack: 'center',
|
hpack: 'center',
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Box(),
|
Box(),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
for (let i = 0; i < buttons.length; ++i) {
|
for (let i = 0; i < buttons.length; ++i) {
|
||||||
if (i !== buttons.length - 1) {
|
if (i === buttons.length - 1) {
|
||||||
widget.children[0].add(buttons[i]);
|
widget.children[0].add(buttons[i]);
|
||||||
widget.children[0].add(Separator(28));
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
widget.children[0].add(buttons[i]);
|
widget.children[0].add(buttons[i]);
|
||||||
|
widget.children[0].add(Separator(SPACING));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return widget;
|
return widget;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -148,24 +176,40 @@ const FirstRow = () => Row({
|
||||||
|
|
||||||
GridButton({
|
GridButton({
|
||||||
command: () => Network.toggleWifi(),
|
command: () => Network.toggleWifi(),
|
||||||
|
|
||||||
secondaryCommand: () => {
|
secondaryCommand: () => {
|
||||||
execAsync(['bash', '-c', 'nm-connection-editor'])
|
execAsync(['bash', '-c', 'nm-connection-editor'])
|
||||||
.catch(print);
|
.catch(print);
|
||||||
},
|
},
|
||||||
icon: [Network, icon => icon.icon = Network.wifi?.iconName],
|
|
||||||
indicator: [Network, self => self.label = Network.wifi?.ssid || Network.wired?.internet],
|
icon: [Network, (icon) => {
|
||||||
|
icon.icon = Network.wifi?.iconName;
|
||||||
|
}],
|
||||||
|
|
||||||
|
indicator: [Network, (self) => {
|
||||||
|
self.label = Network.wifi?.ssid || Network.wired?.internet;
|
||||||
|
}],
|
||||||
|
|
||||||
menu: Box({
|
menu: Box({
|
||||||
className: 'menu',
|
className: 'menu',
|
||||||
vertical: true,
|
vertical: true,
|
||||||
connections: [[Network, box => box.children =
|
|
||||||
Network.wifi?.access_points.map(ap => EventBox({
|
connections: [[Network, (box) => {
|
||||||
|
box.children = Network.wifi
|
||||||
|
?.access_points.map((ap) => EventBox({
|
||||||
isButton: true,
|
isButton: true,
|
||||||
on_clicked: () => execAsync(`nmcli device wifi connect ${ap.bssid}`).catch(print),
|
|
||||||
|
on_clicked: () => {
|
||||||
|
execAsync(`nmcli device wifi
|
||||||
|
connect ${ap.bssid}`).catch(print);
|
||||||
|
},
|
||||||
child: Box({
|
child: Box({
|
||||||
|
|
||||||
children: [
|
children: [
|
||||||
Icon(ap.iconName),
|
Icon(ap.iconName),
|
||||||
|
|
||||||
Label(ap.ssid || ''),
|
Label(ap.ssid || ''),
|
||||||
|
|
||||||
ap.active && Icon({
|
ap.active && Icon({
|
||||||
icon: 'object-select-symbolic',
|
icon: 'object-select-symbolic',
|
||||||
hexpand: true,
|
hexpand: true,
|
||||||
|
@ -173,8 +217,8 @@ const FirstRow = () => Row({
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
})),
|
}));
|
||||||
]],
|
}]],
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
@ -183,45 +227,54 @@ const FirstRow = () => Row({
|
||||||
execAsync(['bash', '-c', '$AGS_PATH/qs-toggles.sh blue-toggle'])
|
execAsync(['bash', '-c', '$AGS_PATH/qs-toggles.sh blue-toggle'])
|
||||||
.catch(print);
|
.catch(print);
|
||||||
},
|
},
|
||||||
|
|
||||||
secondaryCommand: () => {
|
secondaryCommand: () => {
|
||||||
execAsync(['bash', '-c', 'blueberry'])
|
execAsync(['bash', '-c', 'blueberry'])
|
||||||
.catch(print);
|
.catch(print);
|
||||||
},
|
},
|
||||||
icon: [Bluetooth, self => {
|
|
||||||
|
icon: [Bluetooth, (self) => {
|
||||||
if (Bluetooth.enabled) {
|
if (Bluetooth.enabled) {
|
||||||
self.icon = 'bluetooth-active-symbolic';
|
self.icon = 'bluetooth-active-symbolic';
|
||||||
execAsync(['bash', '-c', 'echo > $HOME/.config/.bluetooth'])
|
execAsync(['bash', '-c',
|
||||||
.catch(print);
|
'echo > $HOME/.config/.bluetooth']).catch(print);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
self.icon = 'bluetooth-disabled-symbolic';
|
self.icon = 'bluetooth-disabled-symbolic';
|
||||||
execAsync(['bash', '-c', 'echo > $HOME/.config/.bluetooth'])
|
execAsync(['bash', '-c',
|
||||||
.catch(print);
|
'echo > $HOME/.config/.bluetooth']).catch(print);
|
||||||
}
|
}
|
||||||
}, 'changed'],
|
}, 'changed'],
|
||||||
indicator: [Bluetooth, self => {
|
|
||||||
if (Bluetooth.connectedDevices[0])
|
indicator: [Bluetooth, (self) => {
|
||||||
|
if (Bluetooth.connectedDevices[0]) {
|
||||||
self.label = String(Bluetooth.connectedDevices[0]);
|
self.label = String(Bluetooth.connectedDevices[0]);
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
self.label = 'Disconnected';
|
self.label = 'Disconnected';
|
||||||
|
}
|
||||||
}, 'changed'],
|
}, 'changed'],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
// TODO: replace with vpn
|
// TODO: replace with vpn
|
||||||
GridButton({
|
GridButton({
|
||||||
command: () => {
|
command: () => {
|
||||||
execAsync(['bash', '-c', '$AGS_PATH/qs-toggles.sh toggle-radio'])
|
execAsync(['bash', '-c',
|
||||||
.catch(print);
|
'$AGS_PATH/qs-toggles.sh toggle-radio']).catch(print);
|
||||||
},
|
},
|
||||||
|
|
||||||
secondaryCommand: () => {
|
secondaryCommand: () => {
|
||||||
execAsync(['notify-send', 'set this up moron'])
|
execAsync(['notify-send', 'set this up moron'])
|
||||||
.catch(print);
|
.catch(print);
|
||||||
},
|
},
|
||||||
icon: [Network, self => {
|
|
||||||
if (Network.wifi.enabled)
|
icon: [Network, (self) => {
|
||||||
|
if (Network.wifi.enabled) {
|
||||||
self.icon = 'airplane-mode-disabled-symbolic';
|
self.icon = 'airplane-mode-disabled-symbolic';
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
self.icon = 'airplane-mode-symbolic';
|
self.icon = 'airplane-mode-symbolic';
|
||||||
|
}
|
||||||
}, 'changed'],
|
}, 'changed'],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
@ -230,11 +283,10 @@ const FirstRow = () => Row({
|
||||||
|
|
||||||
const SecondRow = () => Row({
|
const SecondRow = () => Row({
|
||||||
buttons: [
|
buttons: [
|
||||||
|
|
||||||
GridButton({
|
GridButton({
|
||||||
command: () => {
|
command: () => {
|
||||||
execAsync(['pactl', 'set-sink-mute', '@DEFAULT_SINK@', 'toggle'])
|
execAsync(['pactl', 'set-sink-mute',
|
||||||
.catch(print);
|
'@DEFAULT_SINK@', 'toggle']).catch(print);
|
||||||
},
|
},
|
||||||
|
|
||||||
secondaryCommand: () => {
|
secondaryCommand: () => {
|
||||||
|
@ -242,15 +294,15 @@ const SecondRow = () => Row({
|
||||||
.catch(print);
|
.catch(print);
|
||||||
},
|
},
|
||||||
|
|
||||||
icon: [SpeakerIcon, self => {
|
icon: [SpeakerIcon, (self) => {
|
||||||
self.icon = SpeakerIcon.value;
|
self.icon = SpeakerIcon.value;
|
||||||
}],
|
}],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
GridButton({
|
GridButton({
|
||||||
command: () => {
|
command: () => {
|
||||||
execAsync(['pactl', 'set-source-mute', '@DEFAULT_SOURCE@', 'toggle'])
|
execAsync(['pactl', 'set-source-mute',
|
||||||
.catch(print);
|
'@DEFAULT_SOURCE@', 'toggle']).catch(print);
|
||||||
},
|
},
|
||||||
|
|
||||||
secondaryCommand: () => {
|
secondaryCommand: () => {
|
||||||
|
@ -258,7 +310,7 @@ const SecondRow = () => Row({
|
||||||
.catch(print);
|
.catch(print);
|
||||||
},
|
},
|
||||||
|
|
||||||
icon: [MicIcon, self => {
|
icon: [MicIcon, (self) => {
|
||||||
self.icon = MicIcon.value;
|
self.icon = MicIcon.value;
|
||||||
}],
|
}],
|
||||||
}),
|
}),
|
||||||
|
@ -271,7 +323,6 @@ const SecondRow = () => Row({
|
||||||
secondaryCommand: () => App.openWindow('powermenu'),
|
secondaryCommand: () => App.openWindow('powermenu'),
|
||||||
icon: 'system-lock-screen-symbolic',
|
icon: 'system-lock-screen-symbolic',
|
||||||
}),
|
}),
|
||||||
|
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -48,9 +48,12 @@ const QuickSettingsWidget = () => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const TOP_MARGIN = 6;
|
||||||
|
const RIGHT_MARGIN = 5;
|
||||||
|
|
||||||
export default () => PopupWindow({
|
export default () => PopupWindow({
|
||||||
name: 'quick-settings',
|
name: 'quick-settings',
|
||||||
anchor: ['top', 'right'],
|
anchor: ['top', 'right'],
|
||||||
margins: [6, 5, 0],
|
margins: [TOP_MARGIN, RIGHT_MARGIN, 0, 0],
|
||||||
child: QuickSettingsWidget(),
|
child: QuickSettingsWidget(),
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import Audio from 'resource:///com/github/Aylur/ags/service/audio.js';
|
import Audio from 'resource:///com/github/Aylur/ags/service/audio.js';
|
||||||
|
|
||||||
import { Box, Slider, Icon } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Box, Slider, Icon } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
|
|
||||||
|
import Brightness from '../../services/brightness.js';
|
||||||
import { SpeakerIcon } from '../misc/audio-icons.js';
|
import { SpeakerIcon } from '../misc/audio-icons.js';
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,6 +16,7 @@ export default () => Box({
|
||||||
className: 'slider',
|
className: 'slider',
|
||||||
vpack: 'start',
|
vpack: 'start',
|
||||||
hpack: 'center',
|
hpack: 'center',
|
||||||
|
|
||||||
children: [
|
children: [
|
||||||
Icon({
|
Icon({
|
||||||
size: 26,
|
size: 26,
|
||||||
|
@ -24,17 +27,25 @@ export default () => Box({
|
||||||
Slider({
|
Slider({
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
vpack: 'center',
|
vpack: 'center',
|
||||||
|
max: 0.999,
|
||||||
|
draw_value: false,
|
||||||
|
|
||||||
|
onChange: ({ value }) => {
|
||||||
|
Audio.speaker.volume = value;
|
||||||
|
},
|
||||||
|
|
||||||
connections: [
|
connections: [
|
||||||
[Audio, slider => {
|
[Audio, (slider) => {
|
||||||
slider.value = Audio.speaker?.volume;
|
slider.value = Audio.speaker?.volume;
|
||||||
}, 'speaker-changed'],
|
}, 'speaker-changed'],
|
||||||
|
|
||||||
['button-press-event', s => { s.cursor = 'grabbing'; }],
|
['button-press-event', (s) => {
|
||||||
['button-release-event', s => { s.cursor = 'pointer'; }],
|
s.cursor = 'grabbing';
|
||||||
|
}],
|
||||||
|
['button-release-event', (s) => {
|
||||||
|
s.cursor = 'pointer';
|
||||||
|
}],
|
||||||
],
|
],
|
||||||
onChange: ({ value }) => Audio.speaker.volume = value,
|
|
||||||
max: 0.999,
|
|
||||||
draw_value: false,
|
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
@ -43,6 +54,7 @@ export default () => Box({
|
||||||
className: 'slider',
|
className: 'slider',
|
||||||
vpack: 'start',
|
vpack: 'start',
|
||||||
hpack: 'center',
|
hpack: 'center',
|
||||||
|
|
||||||
children: [
|
children: [
|
||||||
Icon({
|
Icon({
|
||||||
className: 'slider-label',
|
className: 'slider-label',
|
||||||
|
@ -52,16 +64,24 @@ export default () => Box({
|
||||||
Slider({
|
Slider({
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
vpack: 'center',
|
vpack: 'center',
|
||||||
onChange: ({ value }) => Brightness.screen = value,
|
draw_value: false,
|
||||||
|
|
||||||
|
onChange: ({ value }) => {
|
||||||
|
Brightness.screen = value;
|
||||||
|
},
|
||||||
|
|
||||||
connections: [
|
connections: [
|
||||||
[Brightness, slider => {
|
[Brightness, (slider) => {
|
||||||
slider.value = Brightness.screen;
|
slider.value = Brightness.screen;
|
||||||
}, 'screen'],
|
}, 'screen'],
|
||||||
|
|
||||||
['button-press-event', s => { s.cursor = 'grabbing'; }],
|
['button-press-event', (s) => {
|
||||||
['button-release-event', s => { s.cursor = 'pointer'; }],
|
s.cursor = 'grabbing';
|
||||||
|
}],
|
||||||
|
['button-release-event', (s) => {
|
||||||
|
s.cursor = 'pointer';
|
||||||
|
}],
|
||||||
],
|
],
|
||||||
draw_value: false,
|
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
import App from 'resource:///com/github/Aylur/ags/app.js';
|
import App from 'resource:///com/github/Aylur/ags/app.js';
|
||||||
import Mpris from 'resource:///com/github/Aylur/ags/service/mpris.js';
|
import Mpris from 'resource:///com/github/Aylur/ags/service/mpris.js';
|
||||||
|
|
||||||
import { CenterBox, Icon, ToggleButton } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { CenterBox, Icon, ToggleButton } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
|
|
||||||
|
|
||||||
export default rev => CenterBox({
|
export default (rev) => CenterBox({
|
||||||
center_widget: ToggleButton({
|
center_widget: ToggleButton({
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
setup: self => {
|
|
||||||
|
setup: (self) => {
|
||||||
// Open at startup if there are players
|
// Open at startup if there are players
|
||||||
const id = Mpris.connect('changed', () => {
|
const id = Mpris.connect('changed', () => {
|
||||||
self.set_active(Mpris.players.length > 0);
|
self.set_active(Mpris.players.length > 0);
|
||||||
|
@ -14,7 +16,7 @@ export default rev => CenterBox({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
connections: [['toggled', self => {
|
connections: [['toggled', (self) => {
|
||||||
if (self.get_active()) {
|
if (self.get_active()) {
|
||||||
self.get_children()[0]
|
self.get_children()[0]
|
||||||
.setCss('-gtk-icon-transform: rotate(0deg);');
|
.setCss('-gtk-icon-transform: rotate(0deg);');
|
||||||
|
@ -28,7 +30,7 @@ export default rev => CenterBox({
|
||||||
}]],
|
}]],
|
||||||
|
|
||||||
child: Icon({
|
child: Icon({
|
||||||
icon: App.configDir + '/icons/down-large.svg',
|
icon: `${App.configDir }/icons/down-large.svg`,
|
||||||
className: 'arrow',
|
className: 'arrow',
|
||||||
css: '-gtk-icon-transform: rotate(180deg);',
|
css: '-gtk-icon-transform: rotate(180deg);',
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import App from 'resource:///com/github/Aylur/ags/app.js';
|
import App from 'resource:///com/github/Aylur/ags/app.js';
|
||||||
import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
|
import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
|
||||||
|
|
||||||
import { execAsync } from 'resource:///com/github/Aylur/ags/utils.js';
|
import { execAsync } from 'resource:///com/github/Aylur/ags/utils.js';
|
||||||
|
|
||||||
import Brightness from '../services/brightness.js';
|
import Brightness from '../services/brightness.js';
|
||||||
|
@ -28,27 +29,33 @@ export default () => {
|
||||||
name: 'oskOn',
|
name: 'oskOn',
|
||||||
gesture: 'DU',
|
gesture: 'DU',
|
||||||
edge: 'B',
|
edge: 'B',
|
||||||
command: 'busctl call --user sm.puri.OSK0 /sm/puri/OSK0 sm.puri.OSK0 SetVisible b true',
|
command: 'busctl call --user sm.puri.OSK0 /sm/puri/OSK0 sm.puri.OSK0 ' +
|
||||||
|
'SetVisible b true',
|
||||||
});
|
});
|
||||||
|
|
||||||
TouchGestures.addGesture({
|
TouchGestures.addGesture({
|
||||||
name: 'oskOff',
|
name: 'oskOff',
|
||||||
gesture: 'UD',
|
gesture: 'UD',
|
||||||
edge: 'B',
|
edge: 'B',
|
||||||
command: 'busctl call --user sm.puri.OSK0 /sm/puri/OSK0 sm.puri.OSK0 SetVisible b false',
|
command: 'busctl call --user sm.puri.OSK0 /sm/puri/OSK0 sm.puri.OSK0 ' +
|
||||||
|
'SetVisible b false',
|
||||||
});
|
});
|
||||||
|
|
||||||
TouchGestures.addGesture({
|
TouchGestures.addGesture({
|
||||||
name: 'swipeSpotify1',
|
name: 'swipeSpotify1',
|
||||||
gesture: 'LR',
|
gesture: 'LR',
|
||||||
edge: 'L',
|
edge: 'L',
|
||||||
command: () => Hyprland.sendMessage('dispatch togglespecialworkspace spot'),
|
command: () => Hyprland.sendMessage(
|
||||||
|
'dispatch togglespecialworkspace spot',
|
||||||
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
TouchGestures.addGesture({
|
TouchGestures.addGesture({
|
||||||
name: 'swipeSpotify2',
|
name: 'swipeSpotify2',
|
||||||
gesture: 'RL',
|
gesture: 'RL',
|
||||||
edge: 'L',
|
edge: 'L',
|
||||||
command: () => Hyprland.sendMessage('dispatch togglespecialworkspace spot'),
|
command: () => Hyprland.sendMessage(
|
||||||
|
'dispatch togglespecialworkspace spot',
|
||||||
|
),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,5 +9,8 @@
|
||||||
"@typescript-eslint/parser": "^6.9.1",
|
"@typescript-eslint/parser": "^6.9.1",
|
||||||
"eslint": "^8.52.0",
|
"eslint": "^8.52.0",
|
||||||
"stylelint-config-standard-scss": "^11.0.0"
|
"stylelint-config-standard-scss": "^11.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@stylistic/eslint-plugin": "^1.4.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,39 +4,51 @@ import { exec, execAsync } from 'resource:///com/github/Aylur/ags/utils.js';
|
||||||
|
|
||||||
const KBD = 'tpacpi::kbd_backlight';
|
const KBD = 'tpacpi::kbd_backlight';
|
||||||
const CAPS = 'input0::capslock';
|
const CAPS = 'input0::capslock';
|
||||||
|
const INTERVAL = 500;
|
||||||
|
|
||||||
class Brightness extends Service {
|
class Brightness extends Service {
|
||||||
static {
|
static {
|
||||||
Service.register(this, {
|
Service.register(this, {
|
||||||
'screen': ['float'],
|
screen: ['float'],
|
||||||
'kbd': ['float'],
|
kbd: ['float'],
|
||||||
'caps': ['int'],
|
caps: ['int'],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_kbd = 0;
|
#kbd = 0;
|
||||||
_screen = 0;
|
#screen = 0;
|
||||||
_caps = 0;
|
#caps = 0;
|
||||||
|
|
||||||
get kbd() { return this._kbd; }
|
get kbd() {
|
||||||
get screen() { return this._screen; }
|
return this.#kbd;
|
||||||
get caps() { return this._caps; }
|
}
|
||||||
|
|
||||||
|
get screen() {
|
||||||
|
return this.#screen;
|
||||||
|
}
|
||||||
|
|
||||||
|
get caps() {
|
||||||
|
return this.#caps;
|
||||||
|
}
|
||||||
|
|
||||||
set kbd(value) {
|
set kbd(value) {
|
||||||
|
this.#kbd = value;
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
set screen(percent) {
|
set screen(percent) {
|
||||||
if (percent < 0)
|
if (percent < 0) {
|
||||||
percent = 0;
|
percent = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (percent > 1)
|
if (percent > 1) {
|
||||||
percent = 1;
|
percent = 1;
|
||||||
|
}
|
||||||
|
|
||||||
execAsync(`brightnessctl s ${percent * 100}% -q`)
|
execAsync(`brightnessctl s ${percent * 100}% -q`)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this._screen = percent;
|
this.#screen = percent;
|
||||||
this.emit('screen', this._screen);
|
this.emit('screen', this.#screen);
|
||||||
})
|
})
|
||||||
.catch(console.error);
|
.catch(console.error);
|
||||||
}
|
}
|
||||||
|
@ -44,29 +56,31 @@ class Brightness extends Service {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
try {
|
try {
|
||||||
this.monitorKbdState();
|
this.#monitorKbdState();
|
||||||
this._caps = Number(exec(`brightnessctl -d ${CAPS} g`));
|
this.#caps = Number(exec(`brightnessctl -d ${CAPS} g`));
|
||||||
this._screen = Number(exec('brightnessctl g')) / Number(exec('brightnessctl m'));
|
this.#screen = Number(exec('brightnessctl g')) /
|
||||||
} catch (error) {
|
Number(exec('brightnessctl m'));
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
console.error('missing dependancy: brightnessctl');
|
console.error('missing dependancy: brightnessctl');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchCapsState() {
|
fetchCapsState() {
|
||||||
execAsync(`brightnessctl -d ${CAPS} g`)
|
execAsync(`brightnessctl -d ${CAPS} g`)
|
||||||
.then(out => {
|
.then((out) => {
|
||||||
this._caps = out;
|
this.#caps = out;
|
||||||
this.emit('caps', this._caps);
|
this.emit('caps', this.#caps);
|
||||||
})
|
})
|
||||||
.catch(logError);
|
.catch(logError);
|
||||||
}
|
}
|
||||||
|
|
||||||
monitorKbdState() {
|
#monitorKbdState() {
|
||||||
Variable(0, {
|
Variable(0, {
|
||||||
poll: [500, `brightnessctl -d ${KBD} g`, out => {
|
poll: [INTERVAL, `brightnessctl -d ${KBD} g`, (out) => {
|
||||||
if (out !== this._kbd) {
|
if (out !== this.#kbd) {
|
||||||
this._kbd = out;
|
this.#kbd = out;
|
||||||
this.emit('kbd', this._kbd);
|
this.emit('kbd', this.#kbd);
|
||||||
}
|
}
|
||||||
}],
|
}],
|
||||||
});
|
});
|
||||||
|
@ -74,4 +88,5 @@ class Brightness extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
const brightnessService = new Brightness();
|
const brightnessService = new Brightness();
|
||||||
|
|
||||||
export default brightnessService;
|
export default brightnessService;
|
||||||
|
|
|
@ -34,28 +34,36 @@ class Pointers extends Service {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
proc = undefined;
|
#process;
|
||||||
output = '';
|
#lastLine = '';
|
||||||
devices = [];
|
#pointers = [];
|
||||||
udevClient = GUdev.Client.new(['input']);
|
#udevClient = GUdev.Client.new(['input']);
|
||||||
|
|
||||||
get process() { return this.proc; }
|
get process() {
|
||||||
get lastLine() { return this.output; }
|
return this.#process;
|
||||||
get pointers() { return this.devices; }
|
}
|
||||||
|
|
||||||
|
get lastLine() {
|
||||||
|
return this.#lastLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
get pointers() {
|
||||||
|
return this.#pointers;
|
||||||
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.initUdevConnection();
|
this.#initUdevConnection();
|
||||||
this.initAppConnection();
|
this.#initAppConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: logitech mouse screws everything up on disconnect
|
// FIXME: logitech mouse screws everything up on disconnect
|
||||||
initUdevConnection() {
|
#initUdevConnection() {
|
||||||
this.getDevices();
|
this.#getDevices();
|
||||||
this.udevClient.connect('uevent', (_, action) => {
|
this.#udevClient.connect('uevent', (_, action) => {
|
||||||
if (action === 'add' || action === 'remove') {
|
if (action === 'add' || action === 'remove') {
|
||||||
this.getDevices();
|
this.getDevices();
|
||||||
if (this.proc) {
|
if (this.#process) {
|
||||||
this.killProc();
|
this.killProc();
|
||||||
this.startProc();
|
this.startProc();
|
||||||
}
|
}
|
||||||
|
@ -63,15 +71,19 @@ class Pointers extends Service {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getDevices() {
|
#getDevices() {
|
||||||
this.devices = [];
|
this.#pointers = [];
|
||||||
this.udevClient.query_by_subsystem('input').forEach(dev => {
|
this.#udevClient.query_by_subsystem('input').forEach((dev) => {
|
||||||
const isPointer = UDEV_POINTERS.some(p => dev.has_property(p));
|
const isPointer = UDEV_POINTERS.some((p) => dev.has_property(p));
|
||||||
|
|
||||||
if (isPointer) {
|
if (isPointer) {
|
||||||
const hasEventFile = dev.has_property('DEVNAME') &&
|
const hasEventFile = dev.has_property('DEVNAME') &&
|
||||||
dev.get_property('DEVNAME').includes('event');
|
dev.get_property('DEVNAME')
|
||||||
if (hasEventFile)
|
.includes('event');
|
||||||
this.devices.push(dev.get_property('DEVNAME'));
|
|
||||||
|
if (hasEventFile) {
|
||||||
|
this.#pointers.push(dev.get_property('DEVNAME'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -79,51 +91,54 @@ class Pointers extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
startProc() {
|
startProc() {
|
||||||
if (this.proc)
|
if (this.#process) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const args = [];
|
const args = [];
|
||||||
this.devices.forEach(dev => {
|
|
||||||
|
this.#pointers.forEach((dev) => {
|
||||||
args.push('--device');
|
args.push('--device');
|
||||||
args.push(dev);
|
args.push(dev);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.proc = subprocess(
|
this.#process = subprocess(
|
||||||
['libinput', 'debug-events', ...args],
|
['libinput', 'debug-events', ...args],
|
||||||
output => {
|
(output) => {
|
||||||
if (output.includes('cancelled'))
|
if (output.includes('cancelled')) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (ON_RELEASE_TRIGGERS.some(p => output.includes(p))) {
|
if (ON_RELEASE_TRIGGERS.some((p) => output.includes(p))) {
|
||||||
this.output = output;
|
this.#lastLine = output;
|
||||||
this.detectClickedOutside('released');
|
Pointers.detectClickedOutside('released');
|
||||||
this.emit('released', output);
|
this.emit('released', output);
|
||||||
this.emit('new-line', output);
|
this.emit('new-line', output);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ON_CLICK_TRIGGERS.some(p => output.includes(p))) {
|
if (ON_CLICK_TRIGGERS.some((p) => output.includes(p))) {
|
||||||
this.output = output;
|
this.#lastLine = output;
|
||||||
this.detectClickedOutside('clicked');
|
Pointers.detectClickedOutside('clicked');
|
||||||
this.emit('clicked', output);
|
this.emit('clicked', output);
|
||||||
this.emit('new-line', output);
|
this.emit('new-line', output);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
err => logError(err),
|
(err) => logError(err),
|
||||||
);
|
);
|
||||||
this.emit('proc-started', true);
|
this.emit('proc-started', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
killProc() {
|
killProc() {
|
||||||
if (this.proc) {
|
if (this.#process) {
|
||||||
this.proc.force_exit();
|
this.#process.force_exit();
|
||||||
this.proc = undefined;
|
this.#process = null;
|
||||||
this.emit('proc-destroyed', true);
|
this.emit('proc-destroyed', true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
initAppConnection() {
|
#initAppConnection() {
|
||||||
App.connect('window-toggled', () => {
|
App.connect('window-toggled', () => {
|
||||||
const anyVisibleAndClosable = Array.from(App.windows).some(w => {
|
const anyVisibleAndClosable = Array.from(App.windows).some((w) => {
|
||||||
const closable = w[1].closeOnUnfocus &&
|
const closable = w[1].closeOnUnfocus &&
|
||||||
!(w[1].closeOnUnfocus === 'none' ||
|
!(w[1].closeOnUnfocus === 'none' ||
|
||||||
w[1].closeOnUnfocus === 'stay');
|
w[1].closeOnUnfocus === 'stay');
|
||||||
|
@ -131,51 +146,57 @@ class Pointers extends Service {
|
||||||
return w[1].visible && closable;
|
return w[1].visible && closable;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (anyVisibleAndClosable)
|
if (anyVisibleAndClosable) {
|
||||||
this.startProc();
|
this.startProc();
|
||||||
|
}
|
||||||
|
|
||||||
else
|
else {
|
||||||
this.killProc();
|
this.killProc();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
detectClickedOutside(clickStage) {
|
static detectClickedOutside(clickStage) {
|
||||||
const toClose = Array.from(App.windows).some(w => {
|
const toClose = Array.from(App.windows).some((w) => {
|
||||||
const closable = (w[1].closeOnUnfocus &&
|
const closable = (w[1].closeOnUnfocus &&
|
||||||
w[1].closeOnUnfocus === clickStage);
|
w[1].closeOnUnfocus === clickStage);
|
||||||
|
|
||||||
return w[1].visible && closable;
|
return w[1].visible && closable;
|
||||||
});
|
});
|
||||||
if (!toClose)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Hyprland.sendMessage('j/layers').then(layers => {
|
if (!toClose) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Hyprland.sendMessage('j/layers').then((layers) => {
|
||||||
layers = JSON.parse(layers);
|
layers = JSON.parse(layers);
|
||||||
|
|
||||||
Hyprland.sendMessage('j/cursorpos').then(pos => {
|
Hyprland.sendMessage('j/cursorpos').then((pos) => {
|
||||||
pos = JSON.parse(pos);
|
pos = JSON.parse(pos);
|
||||||
|
|
||||||
Object.values(layers).forEach(key => {
|
Object.values(layers).forEach((key) => {
|
||||||
const bar = key['levels']['3']
|
const bar = key.levels['3']
|
||||||
.find(n => n.namespace === 'bar');
|
.find((n) => n.namespace === 'bar');
|
||||||
|
|
||||||
const widgets = key['levels']['3'].filter(n => {
|
const widgets = key.levels['3'].filter((n) => {
|
||||||
const window = App.getWindow(n.namespace);
|
const window = App.getWindow(n.namespace);
|
||||||
return window.closeOnUnfocus &&
|
|
||||||
window.closeOnUnfocus === clickStage;
|
return window?.closeOnUnfocus &&
|
||||||
|
window?.closeOnUnfocus === clickStage;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (pos.x > bar.x && pos.x < bar.x + bar.w &&
|
if (pos.x > bar.x && pos.x < bar.x + bar.w &&
|
||||||
pos.y > bar.y && pos.y < bar.y + bar.h) {
|
pos.y > bar.y && pos.y < bar.y + bar.h) {
|
||||||
|
|
||||||
// don't handle clicks when on bar
|
// Don't handle clicks when on bar
|
||||||
// TODO: make this configurable
|
// TODO: make this configurable
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
widgets.forEach(w => {
|
widgets.forEach((w) => {
|
||||||
if (!(pos.x > w.x && pos.x < w.x + w.w &&
|
if (!(pos.x > w.x && pos.x < w.x + w.w &&
|
||||||
pos.y > w.y && pos.y < w.y + w.h))
|
pos.y > w.y && pos.y < w.y + w.h)) {
|
||||||
App.closeWindow(w.namespace);
|
App.closeWindow(w.namespace);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -184,5 +205,4 @@ class Pointers extends Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const pointersService = new Pointers();
|
export default new Pointers();
|
||||||
export default pointersService;
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import TouchGestures from './touch-gestures.js';
|
||||||
import { execAsync, subprocess } from 'resource:///com/github/Aylur/ags/utils.js';
|
import { execAsync, subprocess } from 'resource:///com/github/Aylur/ags/utils.js';
|
||||||
import GUdev from 'gi://GUdev';
|
import GUdev from 'gi://GUdev';
|
||||||
|
|
||||||
const ROTATION_MAPPING = {
|
const ROTATION_MAP = {
|
||||||
'normal': 0,
|
'normal': 0,
|
||||||
'right-up': 3,
|
'right-up': 3,
|
||||||
'bottom-up': 2,
|
'bottom-up': 2,
|
||||||
|
@ -28,42 +28,47 @@ class Tablet extends Service {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
tabletMode = false;
|
#tabletMode = false;
|
||||||
autorotate = undefined;
|
#oskState = false;
|
||||||
oskState = false;
|
#autorotate;
|
||||||
blockedInputs = undefined;
|
#blockedInputs;
|
||||||
udevClient = GUdev.Client.new(['input']);
|
#udevClient = GUdev.Client.new(['input']);
|
||||||
|
|
||||||
get tabletMode() { return this.tabletMode; }
|
get tabletMode() {
|
||||||
get oskState() { return this.oskState; }
|
return this.#tabletMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
get oskState() {
|
||||||
|
return this.#oskState;
|
||||||
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.initUdevConnection();
|
this.#initUdevConnection();
|
||||||
this.listenOskState();
|
this.#listenOskState();
|
||||||
}
|
}
|
||||||
|
|
||||||
blockInputs() {
|
#blockInputs() {
|
||||||
if (this.blockedInputs)
|
if (this.#blockedInputs) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.blockedInputs = subprocess(['libinput', 'debug-events', '--grab',
|
this.#blockedInputs = subprocess(['libinput', 'debug-events', '--grab',
|
||||||
'--device', '/dev/input/by-path/platform-i8042-serio-0-event-kbd',
|
'--device', '/dev/input/by-path/platform-i8042-serio-0-event-kbd',
|
||||||
'--device', '/dev/input/by-path/platform-i8042-serio-1-event-mouse',
|
'--device', '/dev/input/by-path/platform-i8042-serio-1-event-mouse',
|
||||||
'--device', '/dev/input/by-path/platform-AMDI0010:02-event-mouse',
|
'--device', '/dev/input/by-path/platform-AMDI0010:02-event-mouse',
|
||||||
'--device', '/dev/input/by-path/platform-thinkpad_acpi-event',
|
'--device', '/dev/input/by-path/platform-thinkpad_acpi-event',
|
||||||
'--device', '/dev/video-bus',
|
'--device', '/dev/video-bus',
|
||||||
'--device', '/dev/touchpad',
|
'--device', '/dev/touchpad'],
|
||||||
],
|
() => { /**/ },
|
||||||
() => {},
|
(err) => logError(err));
|
||||||
err => logError(err));
|
|
||||||
this.emit('inputs-blocked', true);
|
this.emit('inputs-blocked', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
unblockInputs() {
|
#unblockInputs() {
|
||||||
if (this.blockedInputs) {
|
if (this.#blockedInputs) {
|
||||||
this.blockedInputs.force_exit();
|
this.#blockedInputs.force_exit();
|
||||||
this.blockedInputs = undefined;
|
this.#blockedInputs = null;
|
||||||
this.emit('inputs-unblocked', true);
|
this.emit('inputs-unblocked', true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,9 +81,9 @@ class Tablet extends Service {
|
||||||
.catch(print);
|
.catch(print);
|
||||||
|
|
||||||
this.startAutorotate();
|
this.startAutorotate();
|
||||||
this.blockInputs();
|
this.#blockInputs();
|
||||||
|
|
||||||
this.tabletMode = true;
|
this.#tabletMode = true;
|
||||||
this.emit('tablet-mode', true);
|
this.emit('tablet-mode', true);
|
||||||
this.emit('mode-toggled', true);
|
this.emit('mode-toggled', true);
|
||||||
}
|
}
|
||||||
|
@ -91,38 +96,42 @@ class Tablet extends Service {
|
||||||
.catch(print);
|
.catch(print);
|
||||||
|
|
||||||
this.killAutorotate();
|
this.killAutorotate();
|
||||||
this.unblockInputs();
|
this.#unblockInputs();
|
||||||
|
|
||||||
this.tabletMode = false;
|
this.#tabletMode = false;
|
||||||
this.emit('laptop-mode', true);
|
this.emit('laptop-mode', true);
|
||||||
this.emit('mode-toggled', true);
|
this.emit('mode-toggled', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleMode() {
|
toggleMode() {
|
||||||
if (this.tabletMode)
|
if (this.#tabletMode) {
|
||||||
this.setLaptopMode();
|
this.setLaptopMode();
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
this.setTabletMode();
|
this.setTabletMode();
|
||||||
|
}
|
||||||
|
|
||||||
this.emit('mode-toggled', true);
|
this.emit('mode-toggled', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
initUdevConnection() {
|
#initUdevConnection() {
|
||||||
this.getDevices();
|
this.#getDevices();
|
||||||
this.udevClient.connect('uevent', (_, action) => {
|
this.#udevClient.connect('uevent', (_, action) => {
|
||||||
if (action === 'add' || action === 'remove')
|
if (action === 'add' || action === 'remove') {
|
||||||
this.getDevices();
|
this.#getDevices();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getDevices() {
|
#getDevices() {
|
||||||
this.devices = [];
|
this.devices = [];
|
||||||
Hyprland.sendMessage('j/devices').then(out => {
|
Hyprland.sendMessage('j/devices').then((out) => {
|
||||||
const devices = JSON.parse(out);
|
const devices = JSON.parse(out);
|
||||||
devices['touch'].forEach(dev => {
|
|
||||||
|
devices.touch.forEach((dev) => {
|
||||||
this.devices.push(dev.name);
|
this.devices.push(dev.name);
|
||||||
});
|
});
|
||||||
devices['tablets'].forEach(dev => {
|
devices.tablets.forEach((dev) => {
|
||||||
this.devices.push(dev.name);
|
this.devices.push(dev.name);
|
||||||
});
|
});
|
||||||
}).catch(print);
|
}).catch(print);
|
||||||
|
@ -131,20 +140,23 @@ class Tablet extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
startAutorotate() {
|
startAutorotate() {
|
||||||
if (this.autorotate)
|
if (this.#autorotate) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.autorotate = subprocess(
|
this.#autorotate = subprocess(
|
||||||
['monitor-sensor'],
|
['monitor-sensor'],
|
||||||
output => {
|
(output) => {
|
||||||
if (output.includes('orientation changed')) {
|
if (output.includes('orientation changed')) {
|
||||||
const orientation = ROTATION_MAPPING[output.split(' ').at(-1)];
|
const orientation = ROTATION_MAP[output.split(' ').at(-1)];
|
||||||
|
|
||||||
Hyprland.sendMessage(`keyword monitor ${SCREEN},transform,${orientation}`)
|
Hyprland.sendMessage(
|
||||||
.catch(print);
|
`keyword monitor ${SCREEN},transform,${orientation}`,
|
||||||
|
).catch(print);
|
||||||
|
|
||||||
const batchRotate = this.devices.map(dev =>
|
const batchRotate = this.devices.map((dev) =>
|
||||||
`keyword device:${dev}:transform ${orientation}; `);
|
`keyword device:${dev}:transform ${orientation}; `);
|
||||||
|
|
||||||
Hyprland.sendMessage(`[[BATCH]] ${batchRotate.flat()}`);
|
Hyprland.sendMessage(`[[BATCH]] ${batchRotate.flat()}`);
|
||||||
|
|
||||||
if (TouchGestures.gestureDaemon) {
|
if (TouchGestures.gestureDaemon) {
|
||||||
|
@ -153,40 +165,40 @@ class Tablet extends Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
err => logError(err),
|
(err) => logError(err),
|
||||||
);
|
);
|
||||||
this.emit('autorotate-started', true);
|
this.emit('autorotate-started', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
killAutorotate() {
|
killAutorotate() {
|
||||||
if (this.autorotate) {
|
if (this.#autorotate) {
|
||||||
this.autorotate.force_exit();
|
this.#autorotate.force_exit();
|
||||||
this.autorotate = undefined;
|
this.#autorotate = null;
|
||||||
this.emit('autorotate-destroyed', true);
|
this.emit('autorotate-destroyed', true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
listenOskState() {
|
#listenOskState() {
|
||||||
subprocess(
|
subprocess(
|
||||||
['bash', '-c', 'busctl monitor --user sm.puri.OSK0'],
|
['bash', '-c', 'busctl monitor --user sm.puri.OSK0'],
|
||||||
output => {
|
(output) => {
|
||||||
if (output.includes('BOOLEAN')) {
|
if (output.includes('BOOLEAN')) {
|
||||||
this.oskState = output.match('true|false')[0] === 'true';
|
this.#oskState = output.match('true|false')[0] === 'true';
|
||||||
this.emit('osk-toggled', this.oskState);
|
this.emit('osk-toggled', this.#oskState);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
err => logError(err),
|
(err) => logError(err),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
openOsk() {
|
static openOsk() {
|
||||||
execAsync(['busctl', 'call', '--user',
|
execAsync(['busctl', 'call', '--user',
|
||||||
'sm.puri.OSK0', '/sm/puri/OSK0', 'sm.puri.OSK0',
|
'sm.puri.OSK0', '/sm/puri/OSK0', 'sm.puri.OSK0',
|
||||||
'SetVisible', 'b', 'true'])
|
'SetVisible', 'b', 'true'])
|
||||||
.catch(print);
|
.catch(print);
|
||||||
}
|
}
|
||||||
|
|
||||||
closeOsk() {
|
static closeOsk() {
|
||||||
execAsync(['busctl', 'call', '--user',
|
execAsync(['busctl', 'call', '--user',
|
||||||
'sm.puri.OSK0', '/sm/puri/OSK0', 'sm.puri.OSK0',
|
'sm.puri.OSK0', '/sm/puri/OSK0', 'sm.puri.OSK0',
|
||||||
'SetVisible', 'b', 'false'])
|
'SetVisible', 'b', 'false'])
|
||||||
|
@ -194,12 +206,15 @@ class Tablet extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleOsk() {
|
toggleOsk() {
|
||||||
if (this.oskState)
|
if (this.#oskState) {
|
||||||
this.closeOsk();
|
Tablet.closeOsk();
|
||||||
else
|
}
|
||||||
this.openOsk();
|
else {
|
||||||
|
Tablet.openOsk();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const tabletService = new Tablet();
|
const tabletService = new Tablet();
|
||||||
|
|
||||||
export default tabletService;
|
export default tabletService;
|
||||||
|
|
|
@ -14,22 +14,22 @@ const GESTURE_VERIF = [
|
||||||
'ULDR', // Up to Left to Down to Right (counter-clockwise from Up)
|
'ULDR', // Up to Left to Down to Right (counter-clockwise from Up)
|
||||||
];
|
];
|
||||||
const EDGE_VERIF = [
|
const EDGE_VERIF = [
|
||||||
'*', // any
|
'*', // Any
|
||||||
'N', // none
|
'N', // None
|
||||||
'L', // left
|
'L', // Left
|
||||||
'R', // right
|
'R', // Right
|
||||||
'T', // top
|
'T', // Top
|
||||||
'B', // bottom
|
'B', // Bottom
|
||||||
'TL', // top left
|
'TL', // Top left
|
||||||
'TR', // top right
|
'TR', // Top right
|
||||||
'BL', // bottom left
|
'BL', // Bottom left
|
||||||
'BR', // bottom right
|
'BR', // Bottom right
|
||||||
];
|
];
|
||||||
const DISTANCE_VERIF = [
|
const DISTANCE_VERIF = [
|
||||||
'*', // any
|
'*', // Any
|
||||||
'S', // short
|
'S', // Short
|
||||||
'M', // medium
|
'M', // Medium
|
||||||
'L', // large
|
'L', // Large
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
|
@ -43,13 +43,11 @@ class TouchGestures extends Service {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
gestures = new Map();
|
#gestures = new Map();
|
||||||
gestureDaemon = undefined;
|
#gestureDaemon;
|
||||||
|
|
||||||
get gestures() { return this.gestures; }
|
get gestures() {
|
||||||
|
return this.#gestures;
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addGesture({
|
addGesture({
|
||||||
|
@ -63,18 +61,21 @@ class TouchGestures extends Service {
|
||||||
gesture = String(gesture).toUpperCase();
|
gesture = String(gesture).toUpperCase();
|
||||||
if (!GESTURE_VERIF.includes(gesture)) {
|
if (!GESTURE_VERIF.includes(gesture)) {
|
||||||
logError('Wrong gesture id');
|
logError('Wrong gesture id');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
edge = String(edge).toUpperCase();
|
edge = String(edge).toUpperCase();
|
||||||
if (!EDGE_VERIF.includes(edge)) {
|
if (!EDGE_VERIF.includes(edge)) {
|
||||||
logError('Wrong edge id');
|
logError('Wrong edge id');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
distance = String(distance).toUpperCase();
|
distance = String(distance).toUpperCase();
|
||||||
if (!DISTANCE_VERIF.includes(distance)) {
|
if (!DISTANCE_VERIF.includes(distance)) {
|
||||||
logError('Wrong distance id');
|
logError('Wrong distance id');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,23 +84,25 @@ class TouchGestures extends Service {
|
||||||
command = `ags -r "${name}()"`;
|
command = `ags -r "${name}()"`;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.gestures.set(name, [
|
this.#gestures.set(name, [
|
||||||
'-g',
|
'-g',
|
||||||
`${nFingers},${gesture},${edge},${distance},${command}`,
|
`${nFingers},${gesture},${edge},${distance},${command}`,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if (this.gestureDaemon)
|
if (this.#gestureDaemon) {
|
||||||
this.killDaemon();
|
this.killDaemon();
|
||||||
|
}
|
||||||
this.startDaemon();
|
this.startDaemon();
|
||||||
}
|
}
|
||||||
|
|
||||||
startDaemon() {
|
startDaemon() {
|
||||||
if (this.gestureDaemon)
|
if (this.#gestureDaemon) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var command = [
|
let command = [
|
||||||
'lisgd', '-d', SCREEN,
|
'lisgd', '-d', SCREEN,
|
||||||
// orientation
|
// Orientation
|
||||||
'-o', '0',
|
'-o', '0',
|
||||||
// Threshold of gesture recognized
|
// Threshold of gesture recognized
|
||||||
'-t', '125',
|
'-t', '125',
|
||||||
|
@ -109,26 +112,27 @@ class TouchGestures extends Service {
|
||||||
'-m', '3200',
|
'-m', '3200',
|
||||||
];
|
];
|
||||||
|
|
||||||
this.gestures.forEach(gesture => {
|
this.#gestures.forEach((gesture) => {
|
||||||
command = command.concat(gesture);
|
command = command.concat(gesture);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.gestureDaemon = subprocess(
|
this.#gestureDaemon = subprocess(
|
||||||
command,
|
command,
|
||||||
() => {},
|
() => { /**/ },
|
||||||
err => logError(err),
|
(err) => logError(err),
|
||||||
);
|
);
|
||||||
this.emit('daemon-started', true);
|
this.emit('daemon-started', true);
|
||||||
}
|
}
|
||||||
|
|
||||||
killDaemon() {
|
killDaemon() {
|
||||||
if (this.gestureDaemon) {
|
if (this.#gestureDaemon) {
|
||||||
this.gestureDaemon.force_exit();
|
this.#gestureDaemon.force_exit();
|
||||||
this.gestureDaemon = undefined;
|
this.#gestureDaemon = null;
|
||||||
this.emit('daemon-destroyed', true);
|
this.emit('daemon-destroyed', true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const touchGesturesService = new TouchGestures();
|
const touchGesturesService = new TouchGestures();
|
||||||
|
|
||||||
export default touchGesturesService;
|
export default touchGesturesService;
|
||||||
|
|
Loading…
Reference in a new issue