refactor(ags): use aylur's lint settings
This commit is contained in:
parent
afe7f10128
commit
127974d0c2
46 changed files with 2732 additions and 2748 deletions
|
@ -4,7 +4,7 @@ import Closer from './js/misc/closer.js';
|
||||||
import Powermenu from './js/powermenu.js';
|
import Powermenu from './js/powermenu.js';
|
||||||
import { Bar } from './js/bar/main.js';
|
import { Bar } from './js/bar/main.js';
|
||||||
import NotifCenter from './js/notifications/center.js';
|
import NotifCenter from './js/notifications/center.js';
|
||||||
import NotifPopups from './js/notifications/popup.js'
|
import NotifPopups from './js/notifications/popup.js';
|
||||||
import Calendar from './js/date.js';
|
import Calendar from './js/date.js';
|
||||||
import QuickSettings from './js/quick-settings/main.js';
|
import QuickSettings from './js/quick-settings/main.js';
|
||||||
import Overview from './js/overview/main.js';
|
import Overview from './js/overview/main.js';
|
||||||
|
@ -21,28 +21,28 @@ Utils.execAsync(['bash', '-c', '$AGS_PATH/startup.sh']).catch(print);
|
||||||
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
style: css,
|
style: css,
|
||||||
notificationPopupTimeout: 5000,
|
notificationPopupTimeout: 5000,
|
||||||
cacheNotificationActions: true,
|
cacheNotificationActions: true,
|
||||||
closeWindowDelay: {
|
closeWindowDelay: {
|
||||||
'quick-settings': 500,
|
'quick-settings': 500,
|
||||||
'notification-center': 500,
|
'notification-center': 500,
|
||||||
'calendar': 500,
|
'calendar': 500,
|
||||||
'powermenu': 500,
|
'powermenu': 500,
|
||||||
'overview': 500,
|
'overview': 500,
|
||||||
'applauncher': 500,
|
'applauncher': 500,
|
||||||
},
|
},
|
||||||
windows: [
|
windows: [
|
||||||
Powermenu(),
|
Powermenu(),
|
||||||
Bar(),
|
Bar(),
|
||||||
Closer(),
|
Closer(),
|
||||||
NotifCenter(),
|
NotifCenter(),
|
||||||
NotifPopups(),
|
NotifPopups(),
|
||||||
Calendar(),
|
Calendar(),
|
||||||
QuickSettings(),
|
QuickSettings(),
|
||||||
Overview(),
|
Overview(),
|
||||||
AppLauncher(),
|
AppLauncher(),
|
||||||
Corners.Bottomleft(),
|
Corners.Bottomleft(),
|
||||||
Corners.Bottomright(),
|
Corners.Bottomright(),
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,118 +5,118 @@ import Separator from '../misc/separator.js';
|
||||||
import PopupWindow from '../misc/popup.js';
|
import PopupWindow from '../misc/popup.js';
|
||||||
|
|
||||||
const icons = {
|
const icons = {
|
||||||
apps: {
|
apps: {
|
||||||
apps: 'view-app-grid-symbolic',
|
apps: 'view-app-grid-symbolic',
|
||||||
search: 'preferences-system-search-symbolic',
|
search: 'preferences-system-search-symbolic',
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const AppItem = (app, window) => {
|
const AppItem = (app, window) => {
|
||||||
if (app.app.get_string('Icon') == 'Nextcloud')
|
if (app.app.get_string('Icon') == 'Nextcloud')
|
||||||
return;
|
return;
|
||||||
|
|
||||||
return Button({
|
return Button({
|
||||||
className: 'app',
|
className: 'app',
|
||||||
connections: [['clicked', () => {
|
connections: [['clicked', () => {
|
||||||
App.closeWindow(window);
|
App.closeWindow(window);
|
||||||
Utils.exec(`hyprctl dispatch exec ${app.executable}`);
|
Utils.exec(`hyprctl dispatch exec ${app.executable}`);
|
||||||
// TODO: focus on new client. Is this only needed after launch?
|
// TODO: focus on new client. Is this only needed after launch?
|
||||||
++app.frequency;
|
++app.frequency;
|
||||||
}]],
|
}]],
|
||||||
child: Box({
|
child: Box({
|
||||||
children: [
|
children: [
|
||||||
Icon({
|
Icon({
|
||||||
icon: app.app.get_string('Icon'),
|
icon: app.app.get_string('Icon'),
|
||||||
size: 42,
|
size: 42,
|
||||||
|
}),
|
||||||
|
Box({
|
||||||
|
vertical: true,
|
||||||
|
children: [
|
||||||
|
Label({
|
||||||
|
className: 'title',
|
||||||
|
label: app.name,
|
||||||
|
xalign: 0,
|
||||||
|
valign: 'center',
|
||||||
|
ellipsize: 3,
|
||||||
|
}),
|
||||||
|
Label({
|
||||||
|
className: 'description',
|
||||||
|
label: app.description || '',
|
||||||
|
wrap: true,
|
||||||
|
xalign: 0,
|
||||||
|
justification: 'left',
|
||||||
|
valign: 'center',
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
}),
|
}),
|
||||||
Box({
|
});
|
||||||
vertical: true,
|
|
||||||
children: [
|
|
||||||
Label({
|
|
||||||
className: 'title',
|
|
||||||
label: app.name,
|
|
||||||
xalign: 0,
|
|
||||||
valign: 'center',
|
|
||||||
ellipsize: 3,
|
|
||||||
}),
|
|
||||||
Label({
|
|
||||||
className: 'description',
|
|
||||||
label: app.description || '',
|
|
||||||
wrap: true,
|
|
||||||
xalign: 0,
|
|
||||||
justification: 'left',
|
|
||||||
valign: 'center',
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const Applauncher = ({ windowName = 'applauncher' } = {}) => {
|
const Applauncher = ({ windowName = 'applauncher' } = {}) => {
|
||||||
const list = Box({ vertical: true });
|
const list = Box({ vertical: true });
|
||||||
const placeholder = Label({
|
const placeholder = Label({
|
||||||
label: " Couldn't find a match",
|
label: " Couldn't find a match",
|
||||||
className: 'placeholder',
|
className: 'placeholder',
|
||||||
});
|
});
|
||||||
const entry = Entry({
|
const entry = Entry({
|
||||||
hexpand: true,
|
hexpand: true,
|
||||||
placeholderText: 'Search',
|
placeholderText: 'Search',
|
||||||
onAccept: ({ text }) => {
|
onAccept: ({ text }) => {
|
||||||
const list = Applications.query(text);
|
const list = Applications.query(text);
|
||||||
if (list[0]) {
|
if (list[0]) {
|
||||||
App.toggleWindow(windowName);
|
App.toggleWindow(windowName);
|
||||||
list[0].launch();
|
list[0].launch();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onChange: ({ text }) => {
|
onChange: ({ text }) => {
|
||||||
list.children = Applications.query(text).map(app => [
|
list.children = Applications.query(text).map(app => [
|
||||||
Separator(4),
|
Separator(4),
|
||||||
AppItem(app, windowName),
|
AppItem(app, windowName),
|
||||||
]).flat();
|
]).flat();
|
||||||
list.add(Separator(4));
|
list.add(Separator(4));
|
||||||
list.show_all();
|
list.show_all();
|
||||||
|
|
||||||
placeholder.visible = list.children.length === 1;
|
placeholder.visible = list.children.length === 1;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
return Box({
|
return Box({
|
||||||
className: 'applauncher',
|
className: 'applauncher',
|
||||||
properties: [['list', list]],
|
properties: [['list', list]],
|
||||||
vertical: true,
|
vertical: true,
|
||||||
children: [
|
|
||||||
Box({
|
|
||||||
className: 'header',
|
|
||||||
children: [
|
children: [
|
||||||
Icon(icons.apps.search),
|
Box({
|
||||||
entry,
|
className: 'header',
|
||||||
|
children: [
|
||||||
|
Icon(icons.apps.search),
|
||||||
|
entry,
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
Scrollable({
|
||||||
|
hscroll: 'never',
|
||||||
|
child: Box({
|
||||||
|
vertical: true,
|
||||||
|
children: [list, placeholder],
|
||||||
|
}),
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
}),
|
connections: [[App, (_b, name, visible) => {
|
||||||
Scrollable({
|
if (name !== windowName)
|
||||||
hscroll: 'never',
|
return;
|
||||||
child: Box({
|
|
||||||
vertical: true,
|
|
||||||
children: [list, placeholder],
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
connections: [[App, (_b, name, visible) => {
|
|
||||||
if (name !== windowName)
|
|
||||||
return;
|
|
||||||
|
|
||||||
entry.set_text('-'); // force onChange
|
entry.set_text('-'); // force onChange
|
||||||
entry.set_text('');
|
entry.set_text('');
|
||||||
if (visible)
|
if (visible)
|
||||||
entry.grab_focus();
|
entry.grab_focus();
|
||||||
}]],
|
}]],
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export default () => PopupWindow({
|
export default () => PopupWindow({
|
||||||
name: 'applauncher',
|
name: 'applauncher',
|
||||||
focusable: true,
|
focusable: true,
|
||||||
child: Applauncher(),
|
child: Applauncher(),
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,52 +5,52 @@ import Separator from '../misc/separator.js';
|
||||||
import EventBox from '../misc/cursorbox.js';
|
import EventBox from '../misc/cursorbox.js';
|
||||||
|
|
||||||
const items = {
|
const items = {
|
||||||
101: 'audio-volume-overamplified-symbolic',
|
101: 'audio-volume-overamplified-symbolic',
|
||||||
67: 'audio-volume-high-symbolic',
|
67: 'audio-volume-high-symbolic',
|
||||||
34: 'audio-volume-medium-symbolic',
|
34: 'audio-volume-medium-symbolic',
|
||||||
1: 'audio-volume-low-symbolic',
|
1: 'audio-volume-low-symbolic',
|
||||||
0: 'audio-volume-muted-symbolic',
|
0: 'audio-volume-muted-symbolic',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const SpeakerIndicator = props => Icon({
|
const SpeakerIndicator = props => Icon({
|
||||||
...props,
|
...props,
|
||||||
icon: '',
|
icon: '',
|
||||||
connections: [[Audio, self => {
|
connections: [[Audio, self => {
|
||||||
if (!Audio.speaker)
|
if (!Audio.speaker)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Audio.speaker.stream.isMuted) {
|
if (Audio.speaker.stream.isMuted) {
|
||||||
self.icon = items[0];
|
self.icon = items[0];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
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)
|
||||||
self.icon = items[threshold + 1];
|
self.icon = items[threshold + 1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 'speaker-changed']],
|
}, 'speaker-changed']],
|
||||||
});
|
});
|
||||||
|
|
||||||
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']],
|
||||||
});
|
});
|
||||||
|
|
||||||
export default () => EventBox({
|
export default () => EventBox({
|
||||||
onPrimaryClickRelease: 'pavucontrol',
|
onPrimaryClickRelease: 'pavucontrol',
|
||||||
className: 'toggle-off',
|
className: 'toggle-off',
|
||||||
child: Box({
|
child: Box({
|
||||||
className: 'audio',
|
className: 'audio',
|
||||||
children: [
|
children: [
|
||||||
SpeakerIndicator(),
|
SpeakerIndicator(),
|
||||||
Separator(5),
|
Separator(5),
|
||||||
SpeakerPercentLabel(),
|
SpeakerPercentLabel(),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,56 +4,56 @@ const { Label, Icon, Stack, Box } = Widget;
|
||||||
import Separator from '../misc/separator.js';
|
import Separator from '../misc/separator.js';
|
||||||
|
|
||||||
const icons = charging => ([
|
const icons = charging => ([
|
||||||
...Array.from({ length: 10 }, (_, i) => i * 10).map(i => ([
|
...Array.from({ length: 10 }, (_, i) => i * 10).map(i => ([
|
||||||
`${i}`, Icon({
|
`${i}`, Icon({
|
||||||
className: `${i} ${charging ? 'charging' : 'discharging'}`,
|
className: `${i} ${charging ? 'charging' : 'discharging'}`,
|
||||||
icon: `battery-level-${i}${charging ? '-charging' : ''}-symbolic`,
|
icon: `battery-level-${i}${charging ? '-charging' : ''}-symbolic`,
|
||||||
}),
|
}),
|
||||||
])),
|
])),
|
||||||
['100', Icon({
|
['100', Icon({
|
||||||
className: `100 ${charging ? 'charging' : 'discharging'}`,
|
className: `100 ${charging ? 'charging' : 'discharging'}`,
|
||||||
icon: `battery-level-100${charging ? '-charged' : ''}-symbolic`,
|
icon: `battery-level-100${charging ? '-charged' : ''}-symbolic`,
|
||||||
})],
|
})],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
||||||
const Indicators = charging => Stack({
|
const Indicators = charging => Stack({
|
||||||
items: icons(charging),
|
items: icons(charging),
|
||||||
connections: [[Battery, stack => {
|
connections: [[Battery, stack => {
|
||||||
stack.shown = `${Math.floor(Battery.percent / 10) * 10}`;
|
stack.shown = `${Math.floor(Battery.percent / 10) * 10}`;
|
||||||
}]],
|
}]],
|
||||||
});
|
});
|
||||||
|
|
||||||
const Indicator = ({
|
const Indicator = ({
|
||||||
charging = Indicators(true),
|
charging = Indicators(true),
|
||||||
discharging = Indicators(false),
|
discharging = Indicators(false),
|
||||||
...props
|
...props
|
||||||
} = {}) => Stack({
|
} = {}) => Stack({
|
||||||
...props,
|
...props,
|
||||||
className: 'battery-indicator',
|
className: 'battery-indicator',
|
||||||
items: [
|
items: [
|
||||||
['true', charging],
|
['true', charging],
|
||||||
['false', discharging],
|
['false', discharging],
|
||||||
],
|
],
|
||||||
connections: [[Battery, stack => {
|
connections: [[Battery, stack => {
|
||||||
stack.shown = `${Battery.charging || Battery.charged}`;
|
stack.shown = `${Battery.charging || Battery.charged}`;
|
||||||
stack.toggleClassName('charging', Battery.charging);
|
stack.toggleClassName('charging', Battery.charging);
|
||||||
stack.toggleClassName('charged', Battery.charged);
|
stack.toggleClassName('charged', Battery.charged);
|
||||||
stack.toggleClassName('low', Battery.percent < 20);
|
stack.toggleClassName('low', Battery.percent < 20);
|
||||||
}]],
|
}]],
|
||||||
});
|
});
|
||||||
|
|
||||||
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}%`]],
|
||||||
});
|
});
|
||||||
|
|
||||||
export default () => Box({
|
export default () => Box({
|
||||||
className: 'toggle-off battery',
|
className: 'toggle-off battery',
|
||||||
children: [
|
children: [
|
||||||
Indicator(),
|
Indicator(),
|
||||||
Separator(5),
|
Separator(5),
|
||||||
LevelLabel(),
|
LevelLabel(),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,30 +6,28 @@ import Heart from './heart.js';
|
||||||
|
|
||||||
|
|
||||||
export default () => Overlay({
|
export default () => Overlay({
|
||||||
tooltipText: 'Brightness',
|
tooltipText: 'Brightness',
|
||||||
child: ProgressBar({
|
child: ProgressBar({
|
||||||
className: 'toggle-off brightness',
|
className: 'toggle-off brightness',
|
||||||
connections: [
|
connections: [
|
||||||
[200, self => {
|
[200, self => {
|
||||||
Utils.execAsync('brightnessctl get').then(out => {
|
Utils.execAsync('brightnessctl get').then(out => {
|
||||||
let br = out / 255;
|
const br = out / 255;
|
||||||
if (br > 0.33) {
|
if (br > 0.33)
|
||||||
self.value = br;
|
self.value = br;
|
||||||
}
|
else
|
||||||
else {
|
self.value = 0.33;
|
||||||
self.value = 0.33;
|
}).catch(print);
|
||||||
}
|
}],
|
||||||
}).catch(print);
|
],
|
||||||
}],
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
overlays: [
|
|
||||||
Box({
|
|
||||||
style: 'color: #CBA6F7;',
|
|
||||||
children: [
|
|
||||||
Separator(25),
|
|
||||||
Heart(),
|
|
||||||
],
|
|
||||||
}),
|
}),
|
||||||
],
|
overlays: [
|
||||||
|
Box({
|
||||||
|
style: 'color: #CBA6F7;',
|
||||||
|
children: [
|
||||||
|
Separator(25),
|
||||||
|
Heart(),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
|
|
@ -14,26 +14,25 @@ const ClockModule = ({
|
||||||
...props,
|
...props,
|
||||||
className: 'clock',
|
className: 'clock',
|
||||||
connections: [
|
connections: [
|
||||||
[interval, self => {
|
[interval, self => {
|
||||||
var time = DateTime.new_now_local();
|
var 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: Box({
|
child: ClockModule({}),
|
||||||
child: ClockModule({}),
|
}),
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,7 +3,7 @@ const { Label } = Widget;
|
||||||
|
|
||||||
|
|
||||||
export default () => Label({
|
export default () => Label({
|
||||||
style: 'color: #CBA6F7; font-size: 18px',
|
style: 'color: #CBA6F7; font-size: 18px',
|
||||||
truncate: 'end',
|
truncate: 'end',
|
||||||
binds: [['label', Hyprland.active.client, 'title']],
|
binds: [['label', Hyprland.active.client, 'title']],
|
||||||
});
|
});
|
||||||
|
|
|
@ -14,82 +14,82 @@ import Gesture from './gesture.js';
|
||||||
// with hyprctl if in fullscreen or not until fullscreen
|
// with hyprctl if in fullscreen or not until fullscreen
|
||||||
// status changes again
|
// status changes again
|
||||||
|
|
||||||
export default (props) => Overlay({
|
export default props => Overlay({
|
||||||
overlays: [
|
overlays: [
|
||||||
RoundedCorner('topleft', { className: 'corner' }),
|
RoundedCorner('topleft', { className: 'corner' }),
|
||||||
RoundedCorner('topright', { className: 'corner' }),
|
RoundedCorner('topright', { className: 'corner' }),
|
||||||
],
|
|
||||||
|
|
||||||
child: Box({
|
|
||||||
style: 'min-height: 1px',
|
|
||||||
hexpand: true,
|
|
||||||
vertical: true,
|
|
||||||
children: [
|
|
||||||
Widget.Revealer({
|
|
||||||
transition: 'slide_down',
|
|
||||||
setup: self => self.revealChild = true,
|
|
||||||
|
|
||||||
properties: [['timeouts', []]],
|
|
||||||
connections: [[Hyprland, self => {
|
|
||||||
Utils.execAsync('hyprctl activewindow -j').then(out => {
|
|
||||||
let client = JSON.parse(out);
|
|
||||||
if (client.fullscreen === Revealed.value)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Revealed.value = client.fullscreen;
|
|
||||||
|
|
||||||
if (Revealed.value) {
|
|
||||||
setTimeout(() => {
|
|
||||||
if (Revealed.value)
|
|
||||||
self.revealChild = false
|
|
||||||
}, 2000);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
self.revealChild = true;
|
|
||||||
}
|
|
||||||
}).catch(print);
|
|
||||||
}]],
|
|
||||||
|
|
||||||
child: Gesture({
|
|
||||||
onHover: () => Hovering.value = true,
|
|
||||||
onHoverLost: self => {
|
|
||||||
Hovering.value = false;
|
|
||||||
if (Revealed.value) {
|
|
||||||
setTimeout(() => {
|
|
||||||
if (!Hovering.value) {
|
|
||||||
self.get_parent().get_parent().children[1].revealChild = true;
|
|
||||||
self.get_parent().revealChild = false;
|
|
||||||
}
|
|
||||||
}, 2000);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
...props,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
|
|
||||||
Widget.Revealer({
|
|
||||||
connections: [[Revealed, self => {
|
|
||||||
if (Revealed.value) {
|
|
||||||
setTimeout(() => {
|
|
||||||
if (Revealed.value)
|
|
||||||
self.revealChild = true;
|
|
||||||
}, 2000);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
self.revealChild = false;
|
|
||||||
}
|
|
||||||
}]],
|
|
||||||
child: EventBox({
|
|
||||||
onHover: self => {
|
|
||||||
Hovering.value = true;
|
|
||||||
self.get_parent().get_parent().children[0].revealChild = true;
|
|
||||||
self.get_parent().revealChild = false;
|
|
||||||
},
|
|
||||||
child: Box({
|
|
||||||
style: 'min-height: 50px;',
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
],
|
],
|
||||||
}),
|
|
||||||
|
child: Box({
|
||||||
|
style: 'min-height: 1px',
|
||||||
|
hexpand: true,
|
||||||
|
vertical: true,
|
||||||
|
children: [
|
||||||
|
Widget.Revealer({
|
||||||
|
transition: 'slide_down',
|
||||||
|
setup: self => self.revealChild = true,
|
||||||
|
|
||||||
|
properties: [['timeouts', []]],
|
||||||
|
connections: [[Hyprland, self => {
|
||||||
|
Utils.execAsync('hyprctl activewindow -j').then(out => {
|
||||||
|
const client = JSON.parse(out);
|
||||||
|
if (client.fullscreen === Revealed.value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Revealed.value = client.fullscreen;
|
||||||
|
|
||||||
|
if (Revealed.value) {
|
||||||
|
Utils.timeout(2000, () => {
|
||||||
|
if (Revealed.value)
|
||||||
|
self.revealChild = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
self.revealChild = true;
|
||||||
|
}
|
||||||
|
}).catch(print);
|
||||||
|
}]],
|
||||||
|
|
||||||
|
child: Gesture({
|
||||||
|
onHover: () => Hovering.value = true,
|
||||||
|
onHoverLost: self => {
|
||||||
|
Hovering.value = false;
|
||||||
|
if (Revealed.value) {
|
||||||
|
Utils.timeout(2000, () => {
|
||||||
|
if (!Hovering.value) {
|
||||||
|
self.get_parent().get_parent().children[1].revealChild = true;
|
||||||
|
self.get_parent().revealChild = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
...props,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
|
||||||
|
Widget.Revealer({
|
||||||
|
connections: [[Revealed, self => {
|
||||||
|
if (Revealed.value) {
|
||||||
|
Utils.timeout(2000, () => {
|
||||||
|
if (Revealed.value)
|
||||||
|
self.revealChild = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
self.revealChild = false;
|
||||||
|
}
|
||||||
|
}]],
|
||||||
|
child: EventBox({
|
||||||
|
onHover: self => {
|
||||||
|
Hovering.value = true;
|
||||||
|
self.get_parent().get_parent().children[0].revealChild = true;
|
||||||
|
self.get_parent().revealChild = false;
|
||||||
|
},
|
||||||
|
child: Box({
|
||||||
|
style: 'min-height: 50px;',
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,24 +5,23 @@ import Gtk from 'gi://Gtk';
|
||||||
|
|
||||||
|
|
||||||
export default ({
|
export default ({
|
||||||
child,
|
child,
|
||||||
...props
|
...props
|
||||||
}) => {
|
}) => {
|
||||||
let widget = EventBox({
|
const widget = EventBox({
|
||||||
...props,
|
...props,
|
||||||
});
|
});
|
||||||
|
|
||||||
let gesture = Gtk.GestureSwipe.new(widget);
|
const gesture = Gtk.GestureSwipe.new(widget);
|
||||||
|
|
||||||
widget.add(CenterBox({
|
widget.add(CenterBox({
|
||||||
children: [ child ],
|
children: [child],
|
||||||
connections: [[gesture, () => {
|
connections: [[gesture, () => {
|
||||||
const velocity = gesture.get_velocity()[1];
|
const velocity = gesture.get_velocity()[1];
|
||||||
if (velocity < -100)
|
if (velocity < -100)
|
||||||
App.openWindow('quick-settings');
|
App.openWindow('quick-settings');
|
||||||
|
}, 'update']],
|
||||||
|
}));
|
||||||
|
|
||||||
}, 'update']],
|
return widget;
|
||||||
}));
|
|
||||||
|
|
||||||
return widget;
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,24 +6,24 @@ import EventBox from '../misc/cursorbox.js';
|
||||||
|
|
||||||
|
|
||||||
export default () => EventBox({
|
export default () => EventBox({
|
||||||
halign: 'center',
|
halign: 'center',
|
||||||
|
|
||||||
onPrimaryClickRelease: () => {
|
onPrimaryClickRelease: () => {
|
||||||
execAsync(['bash', '-c', '$AGS_PATH/heart.sh toggle']).catch(print);
|
execAsync(['bash', '-c', '$AGS_PATH/heart.sh toggle']).catch(print);
|
||||||
},
|
},
|
||||||
|
|
||||||
child: Box({
|
child: Box({
|
||||||
className: 'heart-toggle',
|
className: 'heart-toggle',
|
||||||
vertical: false,
|
vertical: false,
|
||||||
|
|
||||||
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,30 +1,30 @@
|
||||||
import { Hyprland, Utils, Widget } from '../../imports.js';
|
import { Hyprland, Utils, Widget } from '../../imports.js';
|
||||||
const { Label, Box, Icon } = Widget;
|
const { Label, Box, Icon } = Widget;
|
||||||
|
|
||||||
const DEFAULT_KB = "at-translated-set-2-keyboard";
|
const DEFAULT_KB = 'at-translated-set-2-keyboard';
|
||||||
|
|
||||||
export default () => Box({
|
export default () => Box({
|
||||||
className: 'toggle-off',
|
className: 'toggle-off',
|
||||||
children: [
|
children: [
|
||||||
Icon({
|
Icon({
|
||||||
icon: 'input-keyboard-symbolic',
|
icon: 'input-keyboard-symbolic',
|
||||||
style: 'margin-right: 4px;',
|
style: 'margin-right: 4px;',
|
||||||
}),
|
}),
|
||||||
Label({
|
Label({
|
||||||
connections: [[Hyprland, (self, _n, layout) => {
|
connections: [[Hyprland, (self, _n, layout) => {
|
||||||
if (!layout) {
|
if (!layout) {
|
||||||
let obj = Utils.exec('hyprctl devices -j')
|
const obj = Utils.exec('hyprctl devices -j');
|
||||||
let keyboards = JSON.parse(obj)['keyboards'];
|
const keyboards = JSON.parse(obj)['keyboards'];
|
||||||
let kb = keyboards.find(val => val.name === DEFAULT_KB);
|
const kb = keyboards.find(val => val.name === DEFAULT_KB);
|
||||||
|
|
||||||
layout = kb['active_keymap'];
|
layout = kb['active_keymap'];
|
||||||
|
|
||||||
self.label = layout;
|
self.label = layout;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
self.label = layout;
|
self.label = layout;
|
||||||
}
|
}
|
||||||
}, 'keyboard-layout']],
|
}, 'keyboard-layout']],
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
|
@ -18,70 +18,70 @@ import Revealer from './fullscreen.js';
|
||||||
|
|
||||||
|
|
||||||
export const Bar = () => Window({
|
export const Bar = () => Window({
|
||||||
name: 'bar',
|
name: 'bar',
|
||||||
layer: 'overlay',
|
layer: 'overlay',
|
||||||
anchor: [ 'top', 'left', 'right' ],
|
anchor: ['top', 'left', 'right'],
|
||||||
exclusive: true,
|
exclusive: true,
|
||||||
child: Revealer({
|
child: Revealer({
|
||||||
child: CenterBox({
|
child: CenterBox({
|
||||||
className: 'bar',
|
className: 'bar',
|
||||||
vertical: false,
|
vertical: false,
|
||||||
|
|
||||||
startWidget: Box({
|
startWidget: Box({
|
||||||
halign: 'start',
|
halign: 'start',
|
||||||
children: [
|
children: [
|
||||||
|
|
||||||
OskToggle(),
|
OskToggle(),
|
||||||
|
|
||||||
Separator(12),
|
Separator(12),
|
||||||
|
|
||||||
TabletToggle(),
|
TabletToggle(),
|
||||||
|
|
||||||
Separator(12),
|
Separator(12),
|
||||||
|
|
||||||
SysTray(),
|
SysTray(),
|
||||||
|
|
||||||
Audio(),
|
Audio(),
|
||||||
|
|
||||||
Separator(12),
|
Separator(12),
|
||||||
|
|
||||||
Brightness(),
|
Brightness(),
|
||||||
|
|
||||||
Separator(12),
|
Separator(12),
|
||||||
|
|
||||||
Workspaces(),
|
Workspaces(),
|
||||||
|
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
centerWidget: Box({
|
centerWidget: Box({
|
||||||
children: [
|
children: [
|
||||||
CurrentWindow(),
|
CurrentWindow(),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
endWidget: Box({
|
endWidget: Box({
|
||||||
halign: 'end',
|
halign: 'end',
|
||||||
children: [
|
children: [
|
||||||
Battery(),
|
Battery(),
|
||||||
|
|
||||||
Separator(12),
|
Separator(12),
|
||||||
|
|
||||||
//KeyboardLayout(),
|
//KeyboardLayout(),
|
||||||
|
|
||||||
//Separator(12),
|
//Separator(12),
|
||||||
|
|
||||||
Clock(),
|
Clock(),
|
||||||
|
|
||||||
Separator(12),
|
Separator(12),
|
||||||
|
|
||||||
NotifButton(),
|
NotifButton(),
|
||||||
|
|
||||||
Separator(12),
|
Separator(12),
|
||||||
|
|
||||||
QsToggle(),
|
QsToggle(),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,42 +6,40 @@ import EventBox from '../misc/cursorbox.js';
|
||||||
|
|
||||||
|
|
||||||
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(28),
|
||||||
|
|
||||||
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(8),
|
||||||
|
|
||||||
|
Label({
|
||||||
|
binds: [
|
||||||
|
['label', Notifications, 'notifications', n => String(n.length)],
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
|
||||||
Label({
|
|
||||||
binds: [
|
|
||||||
['label', Notifications, 'notifications', n => String(n.length)],
|
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,29 +6,29 @@ import EventBox from '../misc/cursorbox.js';
|
||||||
|
|
||||||
|
|
||||||
export default () => EventBox({
|
export default () => EventBox({
|
||||||
className: 'toggle-off',
|
className: 'toggle-off',
|
||||||
setup: self => {
|
setup: self => {
|
||||||
subprocess(
|
subprocess(
|
||||||
['bash', '-c', '$AGS_PATH/osk-toggle.sh getState'],
|
['bash', '-c', '$AGS_PATH/osk-toggle.sh getState'],
|
||||||
(output) => self.toggleClassName('toggle-on', output === 'Running'),
|
output => self.toggleClassName('toggle-on', output === 'Running'),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
onPrimaryClickRelease: self => {
|
onPrimaryClickRelease: self => {
|
||||||
subprocess(
|
subprocess(
|
||||||
['bash', '-c', '$AGS_PATH/osk-toggle.sh toggle'],
|
['bash', '-c', '$AGS_PATH/osk-toggle.sh toggle'],
|
||||||
(output) => self.toggleClassName('toggle-on', output !== 'Running'),
|
output => self.toggleClassName('toggle-on', output !== 'Running'),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
child: Box({
|
child: Box({
|
||||||
className: 'osk-toggle',
|
className: 'osk-toggle',
|
||||||
vertical: false,
|
vertical: false,
|
||||||
|
|
||||||
children: [
|
children: [
|
||||||
Label({
|
Label({
|
||||||
label: " ",
|
label: ' ',
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,17 +5,17 @@ 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,
|
||||||
child: Label({
|
child: Label({
|
||||||
label: " ",
|
label: ' ',
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { SystemTray, Widget } from '../../imports.js';
|
import { SystemTray, Utils, Widget } from '../../imports.js';
|
||||||
const { Box, Revealer, Icon, MenuItem } = Widget;
|
const { Box, Revealer, Icon, MenuItem } = Widget;
|
||||||
|
|
||||||
import Gtk from 'gi://Gtk';
|
import Gtk from 'gi://Gtk';
|
||||||
|
@ -7,70 +7,70 @@ import Separator from '../misc/separator.js';
|
||||||
|
|
||||||
|
|
||||||
const SysTrayItem = item => MenuItem({
|
const SysTrayItem = item => MenuItem({
|
||||||
className: 'tray-item',
|
className: 'tray-item',
|
||||||
child: Revealer({
|
child: Revealer({
|
||||||
transition: 'slide_right',
|
transition: 'slide_right',
|
||||||
child: Icon({
|
child: Icon({
|
||||||
size: 24,
|
size: 24,
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
}),
|
submenu: item.menu,
|
||||||
submenu: item.menu,
|
connections: [[item, btn => {
|
||||||
connections: [[item, btn => {
|
btn.child.child.icon = item.icon;
|
||||||
btn.child.child.icon = item.icon;
|
btn.tooltipMarkup = item.tooltipMarkup;
|
||||||
btn.tooltipMarkup = item.tooltipMarkup;
|
}]],
|
||||||
}]]
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const SysTray = () => {
|
const SysTray = () => {
|
||||||
let widget = Gtk.MenuBar.new();
|
const widget = Gtk.MenuBar.new();
|
||||||
|
|
||||||
// Properties
|
// Properties
|
||||||
widget._items = new Map();
|
widget._items = new Map();
|
||||||
|
|
||||||
widget._onAdded = (id) => {
|
widget._onAdded = id => {
|
||||||
const item = SystemTray.getItem(id);
|
const item = SystemTray.getItem(id);
|
||||||
if (widget._items.has(id) || !item)
|
if (widget._items.has(id) || !item)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const w = SysTrayItem(item);
|
const w = SysTrayItem(item);
|
||||||
widget._items.set(id, w);
|
widget._items.set(id, w);
|
||||||
widget.add(w);
|
widget.add(w);
|
||||||
widget.show_all();
|
widget.show_all();
|
||||||
w.child.revealChild = true;
|
w.child.revealChild = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
widget._onRemoved = (id) => {
|
widget._onRemoved = id => {
|
||||||
if (!widget._items.has(id))
|
if (!widget._items.has(id))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
widget._items.get(id).child.revealChild = false;
|
widget._items.get(id).child.revealChild = false;
|
||||||
setTimeout(() => {
|
Utils.timeout(400, () => {
|
||||||
widget._items.get(id).destroy();
|
widget._items.get(id).destroy();
|
||||||
widget._items.delete(id);
|
widget._items.delete(id);
|
||||||
}, 400);
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Connections
|
// Connections
|
||||||
SystemTray.connect('added', (_, id) => widget._onAdded(id));
|
SystemTray.connect('added', (_, id) => widget._onAdded(id));
|
||||||
SystemTray.connect('removed', (_, id) => widget._onRemoved(id));
|
SystemTray.connect('removed', (_, id) => widget._onRemoved(id));
|
||||||
|
|
||||||
return widget;
|
return widget;
|
||||||
}
|
};
|
||||||
|
|
||||||
export default () => Revealer({
|
export default () => Revealer({
|
||||||
transition: 'slide_right',
|
transition: 'slide_right',
|
||||||
connections: [[SystemTray, rev => {
|
connections: [[SystemTray, rev => {
|
||||||
rev.revealChild = rev.child.children[0].get_children().length > 0;
|
rev.revealChild = rev.child.children[0].get_children().length > 0;
|
||||||
}]],
|
}]],
|
||||||
child: Box({
|
child: Box({
|
||||||
children: [
|
|
||||||
Box({
|
|
||||||
className: 'sys-tray',
|
|
||||||
children: [
|
children: [
|
||||||
SysTray(),
|
Box({
|
||||||
|
className: 'sys-tray',
|
||||||
|
children: [
|
||||||
|
SysTray(),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
Separator(12),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
Separator(12),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,18 +6,18 @@ import EventBox from '../misc/cursorbox.js';
|
||||||
|
|
||||||
|
|
||||||
export default () => EventBox({
|
export default () => EventBox({
|
||||||
className: 'toggle-off',
|
className: 'toggle-off',
|
||||||
onPrimaryClickRelease: self => {
|
onPrimaryClickRelease: self => {
|
||||||
subprocess(
|
subprocess(
|
||||||
['bash', '-c', '$AGS_PATH/tablet-toggle.sh toggle'],
|
['bash', '-c', '$AGS_PATH/tablet-toggle.sh toggle'],
|
||||||
(output) => self.toggleClassName('toggle-on', output == 'Tablet'),
|
output => self.toggleClassName('toggle-on', output == 'Tablet'),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
child: Box({
|
child: Box({
|
||||||
className: 'tablet-toggle',
|
className: 'tablet-toggle',
|
||||||
vertical: false,
|
vertical: false,
|
||||||
child: Label({
|
child: Label({
|
||||||
label: " ",
|
label: ' ',
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,65 +6,64 @@ import EventBox from '../misc/cursorbox.js';
|
||||||
|
|
||||||
|
|
||||||
const Workspace = ({ i } = {}) =>
|
const Workspace = ({ i } = {}) =>
|
||||||
Revealer({
|
Revealer({
|
||||||
transition: "slide_right",
|
transition: 'slide_right',
|
||||||
properties: [['id', i]],
|
properties: [['id', i]],
|
||||||
|
|
||||||
child: EventBox({
|
child: EventBox({
|
||||||
tooltipText: `${i}`,
|
tooltipText: `${i}`,
|
||||||
onPrimaryClickRelease: () => {
|
onPrimaryClickRelease: () => {
|
||||||
execAsync(`hyprctl dispatch workspace ${i}`)
|
execAsync(`hyprctl dispatch workspace ${i}`)
|
||||||
.catch(print);
|
.catch(print);
|
||||||
},
|
},
|
||||||
child: Box({
|
child: Box({
|
||||||
className: 'button',
|
className: 'button',
|
||||||
connections: [[Hyprland, self => {
|
connections: [[Hyprland, self => {
|
||||||
const occupied = Hyprland.getWorkspace(i)?.windows > 0;
|
const occupied = Hyprland.getWorkspace(i)?.windows > 0;
|
||||||
self.toggleClassName('active', Hyprland.active.workspace.id === i);
|
self.toggleClassName('active', Hyprland.active.workspace.id === i);
|
||||||
self.toggleClassName('occupied', occupied);
|
self.toggleClassName('occupied', occupied);
|
||||||
self.toggleClassName('empty', !occupied);
|
self.toggleClassName('empty', !occupied);
|
||||||
}]],
|
}]],
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default () => Box({
|
export default () => Box({
|
||||||
className: 'workspaces',
|
className: 'workspaces',
|
||||||
children: [EventBox({
|
children: [EventBox({
|
||||||
child: Box({
|
child: Box({
|
||||||
properties: [
|
properties: [
|
||||||
['workspaces'],
|
['workspaces'],
|
||||||
|
|
||||||
['refresh', self => {
|
['refresh', self => {
|
||||||
self.children.forEach(rev => rev.reveal_child = false);
|
self.children.forEach(rev => rev.reveal_child = false);
|
||||||
self._workspaces.forEach(ws => {
|
self._workspaces.forEach(ws => {
|
||||||
ws.revealChild = true;
|
ws.revealChild = true;
|
||||||
});
|
});
|
||||||
}],
|
}],
|
||||||
|
|
||||||
['updateWs', self => {
|
['updateWs', self => {
|
||||||
Hyprland.workspaces.forEach(ws => {
|
Hyprland.workspaces.forEach(ws => {
|
||||||
let currentWs = self.children.find(ch => ch._id == ws.id);
|
const currentWs = self.children.find(ch => ch._id == ws.id);
|
||||||
if (!currentWs && ws.id > 0) {
|
if (!currentWs && ws.id > 0)
|
||||||
self.add(Workspace({ i: ws.id}));
|
self.add(Workspace({ i: ws.id }));
|
||||||
}
|
});
|
||||||
});
|
self.show_all();
|
||||||
self.show_all();
|
|
||||||
|
|
||||||
// Make sure the order is correct
|
// Make sure the order is correct
|
||||||
self._workspaces.forEach((workspace, i) => {
|
self._workspaces.forEach((workspace, i) => {
|
||||||
workspace.get_parent().reorder_child(workspace, i);
|
workspace.get_parent().reorder_child(workspace, i);
|
||||||
});
|
});
|
||||||
}],
|
}],
|
||||||
],
|
],
|
||||||
connections: [[Hyprland, self => {
|
connections: [[Hyprland, self => {
|
||||||
self._workspaces = self.children.filter(ch => {
|
self._workspaces = self.children.filter(ch => {
|
||||||
return Hyprland.workspaces.find(ws => ws.id == ch._id)
|
return Hyprland.workspaces.find(ws => ws.id == ch._id);
|
||||||
}).sort((a, b) => a._id - b._id);
|
}).sort((a, b) => a._id - b._id);
|
||||||
|
|
||||||
self._updateWs(self);
|
self._updateWs(self);
|
||||||
self._refresh(self);
|
self._refresh(self);
|
||||||
}]],
|
}]],
|
||||||
}),
|
}),
|
||||||
})],
|
})],
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Widget } from '../imports.js';
|
import { Widget } from '../imports.js';
|
||||||
const { Box, Label } = Widget;
|
const { Box, Label } = Widget;
|
||||||
|
|
||||||
import Gtk from 'gi://Gtk';
|
import Gtk from 'gi://Gtk';
|
||||||
import GLib from 'gi://GLib';
|
import GLib from 'gi://GLib';
|
||||||
const { DateTime } = GLib;
|
const { DateTime } = GLib;
|
||||||
|
|
||||||
|
@ -9,80 +9,80 @@ import PopupWindow from './misc/popup.js';
|
||||||
|
|
||||||
|
|
||||||
const Divider = () => Box({
|
const Divider = () => Box({
|
||||||
className: 'divider',
|
className: 'divider',
|
||||||
vertical: true,
|
vertical: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const Time = () => Box({
|
const Time = () => Box({
|
||||||
className: 'timebox',
|
className: 'timebox',
|
||||||
vertical: true,
|
vertical: true,
|
||||||
children: [
|
children: [
|
||||||
|
|
||||||
Box({
|
Box({
|
||||||
className: 'time-container',
|
className: 'time-container',
|
||||||
halign: 'center',
|
halign: 'center',
|
||||||
valign: 'center',
|
valign: 'center',
|
||||||
children: [
|
children: [
|
||||||
|
|
||||||
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');
|
||||||
}]],
|
}]],
|
||||||
|
}),
|
||||||
|
|
||||||
|
Divider(),
|
||||||
|
|
||||||
|
Label({
|
||||||
|
className: 'content',
|
||||||
|
label: 'minute',
|
||||||
|
connections: [[1000, self => {
|
||||||
|
self.label = DateTime.new_now_local().format('%M');
|
||||||
|
}]],
|
||||||
|
}),
|
||||||
|
|
||||||
|
],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Divider(),
|
Box({
|
||||||
|
className: 'date-container',
|
||||||
Label({
|
halign: 'center',
|
||||||
className: 'content',
|
child: Label({
|
||||||
label: 'minute',
|
style: 'font-size: 20px',
|
||||||
connections: [[1000, self => {
|
label: 'complete date',
|
||||||
self.label = DateTime.new_now_local().format('%M');
|
connections: [[1000, self => {
|
||||||
}]],
|
var time = DateTime.new_now_local();
|
||||||
|
self.label = time.format('%A, %B ') +
|
||||||
|
time.get_day_of_month() +
|
||||||
|
time.format(', %Y');
|
||||||
|
}]],
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
],
|
],
|
||||||
}),
|
|
||||||
|
|
||||||
Box({
|
|
||||||
className: 'date-container',
|
|
||||||
halign: 'center',
|
|
||||||
child: Label({
|
|
||||||
style: 'font-size: 20px',
|
|
||||||
label: 'complete date',
|
|
||||||
connections: [[1000, self => {
|
|
||||||
var time = DateTime.new_now_local();
|
|
||||||
self.label = time.format("%A, %B ") +
|
|
||||||
time.get_day_of_month() +
|
|
||||||
time.format(", %Y");
|
|
||||||
}]],
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const CalendarWidget = () => Box({
|
const CalendarWidget = () => Box({
|
||||||
className: 'cal-box',
|
className: 'cal-box',
|
||||||
child: Widget({
|
child: Widget({
|
||||||
type: Gtk.Calendar,
|
type: Gtk.Calendar,
|
||||||
showDayNames: true,
|
showDayNames: true,
|
||||||
showHeading: true,
|
showHeading: true,
|
||||||
className: 'cal',
|
className: 'cal',
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default () => PopupWindow({
|
export default () => PopupWindow({
|
||||||
anchor: [ 'top', 'right' ],
|
anchor: ['top', 'right'],
|
||||||
margin: [ 8, 182, 0, 0],
|
margin: [8, 182, 0, 0],
|
||||||
name: 'calendar',
|
name: 'calendar',
|
||||||
child: Box({
|
child: Box({
|
||||||
className: 'date',
|
className: 'date',
|
||||||
vertical: true,
|
vertical: true,
|
||||||
children: [
|
children: [
|
||||||
Time(),
|
Time(),
|
||||||
CalendarWidget(),
|
CalendarWidget(),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Widget } from '../../imports.js';
|
import { Utils, Widget } from '../../imports.js';
|
||||||
const { Box, Overlay, EventBox } = Widget;
|
const { Box, Overlay, EventBox } = Widget;
|
||||||
|
|
||||||
import Gtk from 'gi://Gtk';
|
import Gtk from 'gi://Gtk';
|
||||||
|
@ -8,80 +8,84 @@ const OFFSCREEN = 500;
|
||||||
const TRANSITION = 'transition: margin 0.5s ease, opacity 3s ease;';
|
const TRANSITION = 'transition: margin 0.5s ease, opacity 3s ease;';
|
||||||
|
|
||||||
|
|
||||||
export default ({ properties, connections, props } = {}) => {
|
export default ({
|
||||||
let widget = EventBox({});
|
properties,
|
||||||
let gesture = Gtk.GestureDrag.new(widget)
|
connections,
|
||||||
|
props,
|
||||||
|
} = {}) => {
|
||||||
|
const widget = EventBox({});
|
||||||
|
const gesture = Gtk.GestureDrag.new(widget);
|
||||||
|
|
||||||
widget.add(Overlay({
|
widget.add(Overlay({
|
||||||
...props,
|
...props,
|
||||||
properties: [
|
properties: [
|
||||||
...properties,
|
...properties,
|
||||||
['dragging', false],
|
['dragging', false],
|
||||||
],
|
],
|
||||||
child: Box({className: 'player'}),
|
child: Box({ className: 'player' }),
|
||||||
connections: [
|
connections: [
|
||||||
...connections,
|
...connections,
|
||||||
|
|
||||||
[gesture, overlay => {
|
[gesture, overlay => {
|
||||||
if (overlay.list().length <= 1)
|
if (overlay.list().length <= 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
overlay._dragging = true;
|
overlay._dragging = true;
|
||||||
const offset = gesture.get_offset()[1];
|
const offset = gesture.get_offset()[1];
|
||||||
|
|
||||||
let playerBox = overlay.list().at(-1);
|
const playerBox = overlay.list().at(-1);
|
||||||
|
|
||||||
if (offset >= 0) {
|
if (offset >= 0) {
|
||||||
playerBox.setStyle(`margin-left: ${offset}px;
|
playerBox.setStyle(`margin-left: ${offset}px;
|
||||||
margin-right: -${offset}px;
|
margin-right: -${offset}px;
|
||||||
${playerBox._bgStyle}`);
|
${playerBox._bgStyle}`);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
let newOffset = Math.abs(offset);
|
const newOffset = Math.abs(offset);
|
||||||
playerBox.setStyle(`margin-left: -${newOffset}px;
|
playerBox.setStyle(`margin-left: -${newOffset}px;
|
||||||
margin-right: ${newOffset}px;
|
margin-right: ${newOffset}px;
|
||||||
${playerBox._bgStyle}`);
|
${playerBox._bgStyle}`);
|
||||||
}
|
}
|
||||||
overlay._selected = playerBox;
|
overlay._selected = playerBox;
|
||||||
}, 'drag-update'],
|
}, 'drag-update'],
|
||||||
|
|
||||||
[gesture, overlay => {
|
[gesture, overlay => {
|
||||||
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];
|
||||||
|
|
||||||
let playerBox = overlay.list().at(-1);
|
const playerBox = overlay.list().at(-1);
|
||||||
|
|
||||||
if (Math.abs(offset) > MAX_OFFSET) {
|
if (Math.abs(offset) > MAX_OFFSET) {
|
||||||
if (offset >= 0) {
|
if (offset >= 0) {
|
||||||
playerBox.setStyle(`${TRANSITION}
|
playerBox.setStyle(`${TRANSITION}
|
||||||
margin-left: ${OFFSCREEN}px;
|
margin-left: ${OFFSCREEN}px;
|
||||||
margin-right: -${OFFSCREEN}px;
|
margin-right: -${OFFSCREEN}px;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
${playerBox._bgStyle}`);
|
${playerBox._bgStyle}`);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
playerBox.setStyle(`${TRANSITION}
|
playerBox.setStyle(`${TRANSITION}
|
||||||
margin-left: -${OFFSCREEN}px;
|
margin-left: -${OFFSCREEN}px;
|
||||||
margin-right: ${OFFSCREEN}px;
|
margin-right: ${OFFSCREEN}px;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
${playerBox._bgStyle}`);
|
${playerBox._bgStyle}`);
|
||||||
}
|
}
|
||||||
setTimeout(() => {
|
Utils.timeout(500, () => {
|
||||||
overlay.reorder_overlay(playerBox, 0);
|
overlay.reorder_overlay(playerBox, 0);
|
||||||
playerBox.setStyle(playerBox._bgStyle);
|
playerBox.setStyle(playerBox._bgStyle);
|
||||||
overlay._selected = overlay.list().at(-1);
|
overlay._selected = overlay.list().at(-1);
|
||||||
}, 500);
|
});
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
playerBox.setStyle(`${TRANSITION} ${playerBox._bgStyle}`);
|
playerBox.setStyle(`${TRANSITION} ${playerBox._bgStyle}`);
|
||||||
|
}
|
||||||
|
}, 'drag-end'],
|
||||||
|
],
|
||||||
|
}));
|
||||||
|
widget.child.list = () => widget.child.get_children().filter(ch => ch._bgStyle !== undefined);
|
||||||
|
|
||||||
}, 'drag-end'],
|
return widget;
|
||||||
],
|
|
||||||
}));
|
|
||||||
widget.child.list = () => widget.child.get_children().filter(ch => ch._bgStyle !== undefined);
|
|
||||||
|
|
||||||
return widget;
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,341 +9,343 @@ import Separator from '../misc/separator.js';
|
||||||
import EventBox from '../misc/cursorbox.js';
|
import EventBox from '../misc/cursorbox.js';
|
||||||
|
|
||||||
const icons = {
|
const icons = {
|
||||||
mpris: {
|
mpris: {
|
||||||
fallback: 'audio-x-generic-symbolic',
|
fallback: 'audio-x-generic-symbolic',
|
||||||
shuffle: {
|
shuffle: {
|
||||||
enabled: '',
|
enabled: '',
|
||||||
disabled: '',
|
disabled: '',
|
||||||
|
},
|
||||||
|
loop: {
|
||||||
|
none: '',
|
||||||
|
track: '',
|
||||||
|
playlist: '',
|
||||||
|
},
|
||||||
|
playing: ' ',
|
||||||
|
paused: ' ',
|
||||||
|
stopped: ' ',
|
||||||
|
prev: '',
|
||||||
|
next: '',
|
||||||
},
|
},
|
||||||
loop: {
|
};
|
||||||
none: '',
|
|
||||||
track: '',
|
|
||||||
playlist: '',
|
|
||||||
},
|
|
||||||
playing: ' ',
|
|
||||||
paused: ' ',
|
|
||||||
stopped: ' ',
|
|
||||||
prev: '',
|
|
||||||
next: '',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export const CoverArt = (player, props) => CenterBox({
|
export const CoverArt = (player, props) => CenterBox({
|
||||||
...props,
|
...props,
|
||||||
vertical: true,
|
vertical: true,
|
||||||
properties: [['bgStyle', '']],
|
properties: [['bgStyle', '']],
|
||||||
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);
|
||||||
|
|
||||||
self._bgStyle = `background: radial-gradient(circle,
|
self._bgStyle = `background: radial-gradient(circle,
|
||||||
rgba(0, 0, 0, 0.4) 30%,
|
rgba(0, 0, 0, 0.4) 30%,
|
||||||
${player.colors.value.imageAccent}),
|
${player.colors.value.imageAccent}),
|
||||||
url("${player.coverPath}");
|
url("${player.coverPath}");
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-position: center;`;
|
background-position: center;`;
|
||||||
|
|
||||||
if (!self.get_parent()._dragging)
|
if (!self.get_parent()._dragging)
|
||||||
self.setStyle(self._bgStyle);
|
self.setStyle(self._bgStyle);
|
||||||
|
}).catch(err => {
|
||||||
}).catch(err => {if (err !== "") print(err)});
|
if (err !== '')
|
||||||
}]],
|
print(err);
|
||||||
|
});
|
||||||
|
}]],
|
||||||
});
|
});
|
||||||
|
|
||||||
export const TitleLabel = (player, props) => Label({
|
export const TitleLabel = (player, props) => Label({
|
||||||
...props,
|
...props,
|
||||||
xalign: 0,
|
xalign: 0,
|
||||||
maxWidthChars: 40,
|
maxWidthChars: 40,
|
||||||
truncate: 'end',
|
truncate: 'end',
|
||||||
justification: 'left',
|
justification: 'left',
|
||||||
className: 'title',
|
className: 'title',
|
||||||
binds: [['label', player, 'track-title']],
|
binds: [['label', player, 'track-title']],
|
||||||
});
|
});
|
||||||
|
|
||||||
export const ArtistLabel = (player, props) => Label({
|
export const ArtistLabel = (player, props) => Label({
|
||||||
...props,
|
...props,
|
||||||
xalign: 0,
|
xalign: 0,
|
||||||
maxWidthChars: 40,
|
maxWidthChars: 40,
|
||||||
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 } = {}) => {
|
||||||
let MainIcon = Icon({
|
const MainIcon = Icon({
|
||||||
...props,
|
...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
|
lookUpIcon(name) ? self.icon = name
|
||||||
: self.icon = icons.mpris.fallback;
|
: self.icon = icons.mpris.fallback;
|
||||||
}]],
|
}]],
|
||||||
});
|
});
|
||||||
|
|
||||||
return Box({
|
return Box({
|
||||||
connections: [[Mpris, self => {
|
connections: [[Mpris, self => {
|
||||||
let overlays = self.get_parent().get_parent()
|
const overlays = self.get_parent().get_parent()
|
||||||
.get_parent().list();
|
.get_parent().list();
|
||||||
|
|
||||||
let player = overlays.find(overlay => {
|
const player = overlays.find(overlay => {
|
||||||
overlay === self.get_parent().get_parent();
|
overlay === self.get_parent().get_parent();
|
||||||
});
|
});
|
||||||
|
|
||||||
let index = overlays.indexOf(player);
|
const index = overlays.indexOf(player);
|
||||||
|
|
||||||
let 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(MainIcon);
|
children.push(MainIcon);
|
||||||
children.push(Separator(2));
|
children.push(Separator(2));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
children.push(Box({className: 'position-indicator'}));
|
children.push(Box({ className: 'position-indicator' }));
|
||||||
children.push(Separator(2));
|
children.push(Separator(2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.children = children;
|
self.children = children;
|
||||||
}]],
|
}]],
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
// FIXME: get the cursors right or just don't display when disabled
|
// FIXME: get the cursors right or just don't display when disabled
|
||||||
export const PositionSlider = (player, props) => EventBox({
|
export const PositionSlider = (player, props) => EventBox({
|
||||||
child: Slider({
|
child: Slider({
|
||||||
...props,
|
...props,
|
||||||
className: 'position-slider',
|
className: 'position-slider',
|
||||||
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.get_parent().window.set_cursor(Gdk.Cursor
|
slider.get_parent().window.set_cursor(Gdk.Cursor
|
||||||
.new_from_name(display, 'grabbing'));
|
.new_from_name(display, 'grabbing'));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (slider.get_parent() && slider.get_parent().window) {
|
if (slider.get_parent() && slider.get_parent().window) {
|
||||||
slider.get_parent().window.set_cursor(Gdk.Cursor
|
slider.get_parent().window.set_cursor(Gdk.Cursor
|
||||||
.new_from_name(display, 'pointer'));
|
.new_from_name(display, 'pointer'));
|
||||||
}
|
}
|
||||||
|
|
||||||
slider.sensitive = player.length > 0;
|
slider.sensitive = 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'],
|
||||||
[player, s => s._update(s), 'position'],
|
[1000, s => s._update(s)],
|
||||||
[1000, s => s._update(s)],
|
[player.colors, s => {
|
||||||
[player.colors, s => {
|
const c = player.colors.value;
|
||||||
let c = player.colors.value;
|
if (c) {
|
||||||
if (c)
|
s.setCss(`highlight { background-color: ${c.buttonAccent}; }
|
||||||
s.setCss(`highlight { background-color: ${c.buttonAccent}; }
|
slider { background-color: ${c.buttonAccent}; }
|
||||||
slider { background-color: ${c.buttonAccent}; }
|
slider:hover { background-color: ${c.hoverAccent}; }
|
||||||
slider:hover { background-color: ${c.hoverAccent}; }
|
trough { background-color: ${c.buttonText}; }`);
|
||||||
trough { background-color: ${c.buttonText}; }`);
|
}
|
||||||
}],
|
}],
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
function lengthStr(length) {
|
function lengthStr(length) {
|
||||||
const min = Math.floor(length / 60);
|
const min = Math.floor(length / 60);
|
||||||
const sec0 = Math.floor(length % 60) < 10 ? '0' : '';
|
const sec0 = Math.floor(length % 60) < 10 ? '0' : '';
|
||||||
const sec = Math.floor(length % 60);
|
const sec = Math.floor(length % 60);
|
||||||
return `${min}:${sec0}${sec}`;
|
return `${min}:${sec0}${sec}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PositionLabel = player => Label({
|
export const PositionLabel = player => Label({
|
||||||
properties: [['update', self => {
|
properties: [['update', self => {
|
||||||
player.length > 0 ? self.label = lengthStr(player.position)
|
player.length > 0 ? self.label = lengthStr(player.position)
|
||||||
: self.visible = !!player;
|
: self.visible = !!player;
|
||||||
}]],
|
}]],
|
||||||
connections: [
|
connections: [
|
||||||
[player, l => l._update(l), 'position'],
|
[player, l => l._update(l), 'position'],
|
||||||
[1000, l => l._update(l)],
|
[1000, l => l._update(l)],
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
export const LengthLabel = player => Label({
|
export const LengthLabel = player => Label({
|
||||||
connections: [[player, self => {
|
connections: [[player, self => {
|
||||||
player.length > 0 ? self.label = lengthStr(player.length)
|
player.length > 0 ? self.label = lengthStr(player.length)
|
||||||
: self.visible = !!player;
|
: self.visible = !!player;
|
||||||
}]],
|
}]],
|
||||||
});
|
});
|
||||||
|
|
||||||
export const Slash = player => Label({
|
export const Slash = player => Label({
|
||||||
label: '/',
|
label: '/',
|
||||||
connections: [[player, self => {
|
connections: [[player, self => {
|
||||||
self.visible = player.length > 0;
|
self.visible = player.length > 0;
|
||||||
}]],
|
}]],
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: use label instead of stack to fix UI issues
|
// TODO: use label instead of stack to fix UI issues
|
||||||
const PlayerButton = ({ player, items, onClick, prop }) => Button({
|
const PlayerButton = ({ player, items, onClick, prop }) => Button({
|
||||||
child: Stack({ items }),
|
child: Stack({ items }),
|
||||||
onPrimaryClickRelease: () => player[onClick](),
|
onPrimaryClickRelease: () => player[onClick](),
|
||||||
properties: [['hovered', false]],
|
properties: [['hovered', false]],
|
||||||
onHover: self => {
|
onHover: self => {
|
||||||
self._hovered = true;
|
self._hovered = true;
|
||||||
if (! self.child.sensitive || ! self.sensitive) {
|
if (! self.child.sensitive || ! self.sensitive)
|
||||||
self.window.set_cursor(Gdk.Cursor.new_from_name(display, 'not-allowed'));
|
self.window.set_cursor(Gdk.Cursor.new_from_name(display, 'not-allowed'));
|
||||||
}
|
|
||||||
else {
|
|
||||||
self.window.set_cursor(Gdk.Cursor.new_from_name(display, 'pointer'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (prop == 'playBackStatus') {
|
else
|
||||||
items.forEach(item => {
|
self.window.set_cursor(Gdk.Cursor.new_from_name(display, 'pointer'));
|
||||||
item[1].setStyle(`background-color: ${player.colors.value.hoverAccent};
|
|
||||||
color: ${player.colors.value.buttonText};
|
|
||||||
min-height: 40px; min-width: 36px;
|
|
||||||
margin-bottom: 1px; margin-right: 1px;`);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onHoverLost: self => {
|
|
||||||
self._hovered = false;
|
|
||||||
self.window.set_cursor(null);
|
|
||||||
if (prop == 'playBackStatus') {
|
|
||||||
items.forEach(item => {
|
|
||||||
item[1].setStyle(`background-color: ${player.colors.value.buttonAccent};
|
|
||||||
color: ${player.colors.value.buttonText};
|
|
||||||
min-height: 42px; min-width: 38px;`);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
connections: [
|
|
||||||
[player, button => {
|
|
||||||
button.child.shown = `${player[prop]}`;
|
|
||||||
}],
|
|
||||||
|
|
||||||
[player.colors, button => {
|
|
||||||
if (!Mpris.players.find(p => player === p))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (player.colors.value) {
|
|
||||||
if (prop == 'playBackStatus') {
|
if (prop == 'playBackStatus') {
|
||||||
if (button._hovered) {
|
|
||||||
items.forEach(item => {
|
items.forEach(item => {
|
||||||
item[1].setStyle(`background-color: ${player.colors.value.hoverAccent};
|
item[1].setStyle(`background-color: ${player.colors.value.hoverAccent};
|
||||||
color: ${player.colors.value.buttonText};
|
color: ${player.colors.value.buttonText};
|
||||||
min-height: 40px; min-width: 36px;
|
min-height: 40px; min-width: 36px;
|
||||||
margin-bottom: 1px; margin-right: 1px;`);
|
margin-bottom: 1px; margin-right: 1px;`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
},
|
||||||
|
onHoverLost: self => {
|
||||||
|
self._hovered = false;
|
||||||
|
self.window.set_cursor(null);
|
||||||
|
if (prop == 'playBackStatus') {
|
||||||
items.forEach(item => {
|
items.forEach(item => {
|
||||||
item[1].setStyle(`background-color: ${player.colors.value.buttonAccent};
|
item[1].setStyle(`background-color: ${player.colors.value.buttonAccent};
|
||||||
color: ${player.colors.value.buttonText};
|
color: ${player.colors.value.buttonText};
|
||||||
min-height: 42px; min-width: 38px;`);
|
min-height: 42px; min-width: 38px;`);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
},
|
||||||
button.setCss(`* { color: ${player.colors.value.buttonAccent}; }
|
connections: [
|
||||||
*:hover { color: ${player.colors.value.hoverAccent}; }`);
|
[player, button => {
|
||||||
}
|
button.child.shown = `${player[prop]}`;
|
||||||
}
|
}],
|
||||||
}],
|
|
||||||
],
|
[player.colors, button => {
|
||||||
|
if (!Mpris.players.find(p => player === p))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (player.colors.value) {
|
||||||
|
if (prop == 'playBackStatus') {
|
||||||
|
if (button._hovered) {
|
||||||
|
items.forEach(item => {
|
||||||
|
item[1].setStyle(`background-color: ${player.colors.value.hoverAccent};
|
||||||
|
color: ${player.colors.value.buttonText};
|
||||||
|
min-height: 40px; min-width: 36px;
|
||||||
|
margin-bottom: 1px; margin-right: 1px;`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
items.forEach(item => {
|
||||||
|
item[1].setStyle(`background-color: ${player.colors.value.buttonAccent};
|
||||||
|
color: ${player.colors.value.buttonText};
|
||||||
|
min-height: 42px; min-width: 38px;`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
button.setCss(`* { color: ${player.colors.value.buttonAccent}; }
|
||||||
|
*:hover { color: ${player.colors.value.hoverAccent}; }`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
export const ShuffleButton = player => PlayerButton({
|
export const ShuffleButton = player => PlayerButton({
|
||||||
player,
|
player,
|
||||||
items: [
|
items: [
|
||||||
['true', Label({
|
['true', Label({
|
||||||
className: 'shuffle enabled',
|
className: 'shuffle enabled',
|
||||||
label: icons.mpris.shuffle.enabled,
|
label: icons.mpris.shuffle.enabled,
|
||||||
})],
|
})],
|
||||||
['false', Label({
|
['false', Label({
|
||||||
className: 'shuffle disabled',
|
className: 'shuffle disabled',
|
||||||
label: icons.mpris.shuffle.disabled,
|
label: icons.mpris.shuffle.disabled,
|
||||||
})],
|
})],
|
||||||
],
|
],
|
||||||
onClick: 'shuffle',
|
onClick: 'shuffle',
|
||||||
prop: 'shuffleStatus',
|
prop: 'shuffleStatus',
|
||||||
});
|
});
|
||||||
|
|
||||||
export const LoopButton = player => PlayerButton({
|
export const LoopButton = player => PlayerButton({
|
||||||
player,
|
player,
|
||||||
items: [
|
items: [
|
||||||
['None', Label({
|
['None', Label({
|
||||||
className: 'loop none',
|
className: 'loop none',
|
||||||
label: icons.mpris.loop.none,
|
label: icons.mpris.loop.none,
|
||||||
})],
|
})],
|
||||||
['Track', Label({
|
['Track', Label({
|
||||||
className: 'loop track',
|
className: 'loop track',
|
||||||
label: icons.mpris.loop.track,
|
label: icons.mpris.loop.track,
|
||||||
})],
|
})],
|
||||||
['Playlist', Label({
|
['Playlist', Label({
|
||||||
className: 'loop playlist',
|
className: 'loop playlist',
|
||||||
label: icons.mpris.loop.playlist,
|
label: icons.mpris.loop.playlist,
|
||||||
})],
|
})],
|
||||||
],
|
],
|
||||||
onClick: 'loop',
|
onClick: 'loop',
|
||||||
prop: 'loopStatus',
|
prop: 'loopStatus',
|
||||||
});
|
});
|
||||||
|
|
||||||
export const PlayPauseButton = player => PlayerButton({
|
export const PlayPauseButton = player => PlayerButton({
|
||||||
player,
|
player,
|
||||||
items: [
|
items: [
|
||||||
['Playing', Label({
|
['Playing', Label({
|
||||||
className: 'pausebutton playing',
|
className: 'pausebutton playing',
|
||||||
label: icons.mpris.playing,
|
label: icons.mpris.playing,
|
||||||
})],
|
})],
|
||||||
['Paused', Label({
|
['Paused', Label({
|
||||||
className: 'pausebutton paused',
|
className: 'pausebutton paused',
|
||||||
label: icons.mpris.paused,
|
label: icons.mpris.paused,
|
||||||
})],
|
})],
|
||||||
['Stopped', Label({
|
['Stopped', Label({
|
||||||
className: 'pausebutton stopped paused',
|
className: 'pausebutton stopped paused',
|
||||||
label: icons.mpris.stopped,
|
label: icons.mpris.stopped,
|
||||||
})],
|
})],
|
||||||
],
|
],
|
||||||
onClick: 'playPause',
|
onClick: 'playPause',
|
||||||
prop: 'playBackStatus',
|
prop: 'playBackStatus',
|
||||||
});
|
});
|
||||||
|
|
||||||
export const PreviousButton = player => PlayerButton({
|
export const PreviousButton = player => PlayerButton({
|
||||||
player,
|
player,
|
||||||
items: [
|
items: [
|
||||||
['true', Label({
|
['true', Label({
|
||||||
className: 'previous',
|
className: 'previous',
|
||||||
label: icons.mpris.prev,
|
label: icons.mpris.prev,
|
||||||
})],
|
})],
|
||||||
['false', Label({
|
['false', Label({
|
||||||
className: 'previous',
|
className: 'previous',
|
||||||
label: icons.mpris.prev,
|
label: icons.mpris.prev,
|
||||||
})],
|
})],
|
||||||
],
|
],
|
||||||
onClick: 'previous',
|
onClick: 'previous',
|
||||||
prop: 'canGoPrev',
|
prop: 'canGoPrev',
|
||||||
});
|
});
|
||||||
|
|
||||||
export const NextButton = player => PlayerButton({
|
export const NextButton = player => PlayerButton({
|
||||||
player,
|
player,
|
||||||
items: [
|
items: [
|
||||||
['true', Label({
|
['true', Label({
|
||||||
className: 'next',
|
className: 'next',
|
||||||
label: icons.mpris.next,
|
label: icons.mpris.next,
|
||||||
})],
|
})],
|
||||||
['false', Label({
|
['false', Label({
|
||||||
className: 'next',
|
className: 'next',
|
||||||
label: icons.mpris.next,
|
label: icons.mpris.next,
|
||||||
})],
|
})],
|
||||||
],
|
],
|
||||||
onClick: 'next',
|
onClick: 'next',
|
||||||
prop: 'canGoNext',
|
prop: 'canGoNext',
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Mpris, Variable, Widget } from '../../imports.js';
|
import { Mpris, Variable, Widget } from '../../imports.js';
|
||||||
const { Box, CenterBox, Label } = Widget;
|
const { Box, CenterBox } = Widget;
|
||||||
|
|
||||||
import * as mpris from './mpris.js';
|
import * as mpris from './mpris.js';
|
||||||
import PlayerGesture from './gesture.js';
|
import PlayerGesture from './gesture.js';
|
||||||
|
@ -9,148 +9,144 @@ const FAVE_PLAYER = 'org.mpris.MediaPlayer2.spotify';
|
||||||
|
|
||||||
|
|
||||||
const Top = player => Box({
|
const Top = player => Box({
|
||||||
className: 'top',
|
className: 'top',
|
||||||
halign: 'start',
|
halign: 'start',
|
||||||
valign: 'start',
|
valign: 'start',
|
||||||
children: [
|
children: [
|
||||||
mpris.PlayerIcon(player, {
|
mpris.PlayerIcon(player, {
|
||||||
symbolic: false,
|
symbolic: false,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
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',
|
||||||
vertical: true,
|
vertical: true,
|
||||||
halign: 'start',
|
halign: 'start',
|
||||||
valign: 'center',
|
valign: 'center',
|
||||||
hexpand: true,
|
hexpand: true,
|
||||||
children: [
|
children: [
|
||||||
mpris.TitleLabel(player),
|
mpris.TitleLabel(player),
|
||||||
mpris.ArtistLabel(player),
|
mpris.ArtistLabel(player),
|
||||||
],
|
],
|
||||||
|
}),
|
||||||
|
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
null,
|
CenterBox({
|
||||||
null,
|
vertical: true,
|
||||||
],
|
children: [
|
||||||
}),
|
null,
|
||||||
|
mpris.PlayPauseButton(player),
|
||||||
|
null,
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
|
||||||
CenterBox({
|
],
|
||||||
vertical: true,
|
|
||||||
children: [
|
|
||||||
null,
|
|
||||||
mpris.PlayPauseButton(player),
|
|
||||||
null,
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const Bottom = player => Box({
|
const Bottom = player => Box({
|
||||||
className: 'bottom',
|
className: 'bottom',
|
||||||
children: [
|
children: [
|
||||||
mpris.PreviousButton(player, {
|
mpris.PreviousButton(player, {
|
||||||
valign: 'end',
|
valign: 'end',
|
||||||
halign: 'start',
|
halign: 'start',
|
||||||
}),
|
}),
|
||||||
Separator(8),
|
Separator(8),
|
||||||
|
|
||||||
mpris.PositionSlider(player),
|
mpris.PositionSlider(player),
|
||||||
Separator(8),
|
Separator(8),
|
||||||
|
|
||||||
mpris.NextButton(player),
|
mpris.NextButton(player),
|
||||||
Separator(8),
|
Separator(8),
|
||||||
|
|
||||||
mpris.ShuffleButton(player),
|
mpris.ShuffleButton(player),
|
||||||
Separator(8),
|
Separator(8),
|
||||||
|
|
||||||
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),
|
||||||
Bottom(player),
|
Bottom(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],
|
||||||
['selected'],
|
['selected'],
|
||||||
],
|
],
|
||||||
connections: [
|
connections: [
|
||||||
[Mpris, (overlay, busName) => {
|
[Mpris, (overlay, busName) => {
|
||||||
if (overlay._players.has(busName))
|
if (overlay._players.has(busName))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!busName) {
|
if (!busName) {
|
||||||
let player = Mpris.players.find(p => !overlay._players.has(p.busName));
|
const player = Mpris.players.find(p => !overlay._players.has(p.busName));
|
||||||
if (player) {
|
if (player)
|
||||||
busName = player.busName;
|
busName = player.busName;
|
||||||
}
|
else
|
||||||
else {
|
return;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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));
|
||||||
|
|
||||||
let result = [];
|
const result = [];
|
||||||
overlay._players.forEach(widget => {
|
overlay._players.forEach(widget => {
|
||||||
result.push(widget);
|
result.push(widget);
|
||||||
});
|
});
|
||||||
|
|
||||||
overlay.overlays = result;
|
overlay.overlays = result;
|
||||||
|
|
||||||
// Select favorite player at startup
|
// Select favorite player at startup
|
||||||
if (!overlay._setup) {
|
if (!overlay._setup) {
|
||||||
if (overlay._players.has(FAVE_PLAYER)) {
|
if (overlay._players.has(FAVE_PLAYER))
|
||||||
overlay._selected = overlay._players.get(FAVE_PLAYER);
|
overlay._selected = overlay._players.get(FAVE_PLAYER);
|
||||||
}
|
|
||||||
overlay._setup = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (overlay._selected)
|
overlay._setup = true;
|
||||||
overlay.reorder_overlay(overlay._selected, -1);
|
}
|
||||||
|
|
||||||
}, 'player-added'],
|
if (overlay._selected)
|
||||||
|
overlay.reorder_overlay(overlay._selected, -1);
|
||||||
|
}, 'player-added'],
|
||||||
|
|
||||||
|
|
||||||
[Mpris, (overlay, busName) => {
|
[Mpris, (overlay, busName) => {
|
||||||
if (!busName || !overlay._players.has(busName))
|
if (!busName || !overlay._players.has(busName))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
overlay._players.delete(busName);
|
overlay._players.delete(busName);
|
||||||
|
|
||||||
let 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._selected)
|
if (overlay._selected)
|
||||||
overlay.reorder_overlay(overlay._selected, -1);
|
overlay.reorder_overlay(overlay._selected, -1);
|
||||||
|
}, 'player-closed'],
|
||||||
}, 'player-closed'],
|
],
|
||||||
],
|
}),
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,80 +4,82 @@ const { Window, Revealer } = Widget;
|
||||||
import Pointers from '../../services/pointers.js';
|
import Pointers from '../../services/pointers.js';
|
||||||
|
|
||||||
const ALWAYS_OPEN = [
|
const ALWAYS_OPEN = [
|
||||||
'closer',
|
'closer',
|
||||||
'bar',
|
'bar',
|
||||||
'notifications',
|
'notifications',
|
||||||
'cornertl',
|
'cornertl',
|
||||||
'cornertr',
|
'cornertr',
|
||||||
'cornerbl',
|
'cornerbl',
|
||||||
'cornerbr'
|
'cornerbr',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
const closeAll = () => {
|
const closeAll = () => {
|
||||||
App.windows.forEach(w => {
|
App.windows.forEach(w => {
|
||||||
if (!ALWAYS_OPEN.some(window => window === w.name))
|
if (!ALWAYS_OPEN.some(window => window === w.name))
|
||||||
App.closeWindow(w.name)
|
App.closeWindow(w.name);
|
||||||
});
|
});
|
||||||
App.closeWindow('closer');
|
App.closeWindow('closer');
|
||||||
};
|
};
|
||||||
globalThis.closeAll = closeAll;
|
globalThis.closeAll = closeAll;
|
||||||
|
|
||||||
Pointers.connect('new-line', (_, out) => {
|
Pointers.connect('new-line', (_, out) => {
|
||||||
if (out) {
|
if (out) {
|
||||||
Utils.execAsync('hyprctl layers -j').then(layers => {
|
Utils.execAsync('hyprctl layers -j').then(layers => {
|
||||||
layers = JSON.parse(layers);
|
layers = JSON.parse(layers);
|
||||||
|
|
||||||
Utils.execAsync('hyprctl cursorpos -j').then(pos => {
|
Utils.execAsync('hyprctl cursorpos -j').then(pos => {
|
||||||
pos = JSON.parse(pos);
|
pos = JSON.parse(pos);
|
||||||
|
|
||||||
Object.values(layers).forEach(key => {
|
Object.values(layers).forEach(key => {
|
||||||
let bar = key['levels']['3']
|
const bar = key['levels']['3']
|
||||||
.find(n => n.namespace === "bar");
|
.find(n => n.namespace === 'bar');
|
||||||
|
|
||||||
let widgets = key['levels']['3']
|
const widgets = key['levels']['3']
|
||||||
.filter(n => !ALWAYS_OPEN.includes(n.namespace));
|
.filter(n => !ALWAYS_OPEN.includes(n.namespace));
|
||||||
|
|
||||||
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
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
widgets.forEach(l => {
|
widgets.forEach(l => {
|
||||||
if (!(pos.x > l.x && pos.x < l.x + l.w &&
|
if (!(pos.x > l.x && pos.x < l.x + l.w &&
|
||||||
pos.y > l.y && pos.y < l.y + l.h)) {
|
pos.y > l.y && pos.y < l.y + l.h)) {
|
||||||
closeAll();
|
closeAll();
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
});
|
||||||
});
|
}).catch(print);
|
||||||
|
}).catch(print);
|
||||||
}).catch(print);
|
}
|
||||||
}).catch(print);
|
});
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
export default () => Window({
|
export default () => Window({
|
||||||
name: 'closer',
|
name: 'closer',
|
||||||
popup: true,
|
popup: true,
|
||||||
layer: 'top',
|
layer: 'top',
|
||||||
|
|
||||||
child: Revealer({
|
child: Revealer({
|
||||||
connections: [[App, (_, windowName, visible) => {
|
connections: [[App, (_, windowName, visible) => {
|
||||||
if (!Array.from(App.windows).some(w => w[1].visible &&
|
const anyVisibleAndClosable = Array.from(App.windows).some(w => {
|
||||||
!ALWAYS_OPEN.some(window => window === w[0]))) {
|
const isAlwaysOpen = ALWAYS_OPEN.some(window => window === w[0]);
|
||||||
App.closeWindow('closer');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (windowName === 'closer') {
|
return w[1].visible && !isAlwaysOpen;
|
||||||
if (visible)
|
});
|
||||||
Pointers.startProc();
|
|
||||||
else
|
if (!anyVisibleAndClosable)
|
||||||
Pointers.killProc();
|
App.closeWindow('closer');
|
||||||
}
|
|
||||||
}]],
|
if (windowName === 'closer') {
|
||||||
}),
|
if (visible)
|
||||||
|
Pointers.startProc();
|
||||||
|
else
|
||||||
|
Pointers.killProc();
|
||||||
|
}
|
||||||
|
}]],
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,42 +5,39 @@ const display = Gdk.Display.get_default();
|
||||||
|
|
||||||
|
|
||||||
export default ({
|
export default ({
|
||||||
type = "EventBox",
|
type = 'EventBox',
|
||||||
reset = true,
|
reset = true,
|
||||||
...props
|
...props
|
||||||
}) => {
|
}) => {
|
||||||
if (type === "EventBox") {
|
if (type === 'EventBox') {
|
||||||
return Widget.EventBox({
|
return Widget.EventBox({
|
||||||
...props,
|
...props,
|
||||||
onHover: self => {
|
onHover: self => {
|
||||||
if (!self.child.sensitive || !self.sensitive) {
|
if (!self.child.sensitive || !self.sensitive)
|
||||||
self.window.set_cursor(Gdk.Cursor.new_from_name(display, 'not-allowed'));
|
self.window.set_cursor(Gdk.Cursor.new_from_name(display, 'not-allowed'));
|
||||||
}
|
|
||||||
else {
|
else
|
||||||
self.window.set_cursor(Gdk.Cursor.new_from_name(display, 'pointer'));
|
self.window.set_cursor(Gdk.Cursor.new_from_name(display, 'pointer'));
|
||||||
}
|
},
|
||||||
},
|
onHoverLost: self => {
|
||||||
onHoverLost: self => {
|
if (reset)
|
||||||
if (reset)
|
self.window.set_cursor(null);
|
||||||
self.window.set_cursor(null);
|
},
|
||||||
},
|
});
|
||||||
});
|
}
|
||||||
}
|
else {
|
||||||
else {
|
return Widget.Button({
|
||||||
return Widget.Button({
|
...props,
|
||||||
...props,
|
onHover: self => {
|
||||||
onHover: self => {
|
if (!self.child.sensitive || !self.sensitive)
|
||||||
if (!self.child.sensitive || !self.sensitive) {
|
self.window.set_cursor(Gdk.Cursor.new_from_name(display, 'not-allowed'));
|
||||||
self.window.set_cursor(Gdk.Cursor.new_from_name(display, 'not-allowed'));
|
else
|
||||||
}
|
self.window.set_cursor(Gdk.Cursor.new_from_name(display, 'pointer'));
|
||||||
else {
|
},
|
||||||
self.window.set_cursor(Gdk.Cursor.new_from_name(display, 'pointer'));
|
onHoverLost: self => {
|
||||||
}
|
if (reset)
|
||||||
},
|
self.window.set_cursor(null);
|
||||||
onHoverLost: self => {
|
},
|
||||||
if (reset)
|
});
|
||||||
self.window.set_cursor(null);
|
}
|
||||||
},
|
};
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -3,37 +3,37 @@ const { Revealer, Box, Window } = Widget;
|
||||||
|
|
||||||
|
|
||||||
export default ({
|
export default ({
|
||||||
name,
|
|
||||||
child,
|
|
||||||
transition = 'slide_down',
|
|
||||||
onOpen = rev => {},
|
|
||||||
...props
|
|
||||||
}) => {
|
|
||||||
let window = Window({
|
|
||||||
name,
|
name,
|
||||||
popup: true,
|
child,
|
||||||
visible: false,
|
transition = 'slide_down',
|
||||||
layer: 'overlay',
|
onOpen = () => {},
|
||||||
...props,
|
...props
|
||||||
|
}) => {
|
||||||
|
const window = Window({
|
||||||
|
name,
|
||||||
|
popup: true,
|
||||||
|
visible: false,
|
||||||
|
layer: 'overlay',
|
||||||
|
...props,
|
||||||
|
|
||||||
child: Box({
|
child: Box({
|
||||||
style: 'min-height:1px; min-width:1px',
|
style: 'min-height:1px; min-width:1px',
|
||||||
child: Revealer({
|
child: Revealer({
|
||||||
transition,
|
transition,
|
||||||
transitionDuration: 500,
|
transitionDuration: 500,
|
||||||
connections: [[App, (rev, currentName, visible) => {
|
connections: [[App, (rev, currentName, visible) => {
|
||||||
if (currentName === name) {
|
if (currentName === name) {
|
||||||
rev.reveal_child = visible;
|
rev.reveal_child = visible;
|
||||||
onOpen(child);
|
onOpen(child);
|
||||||
|
|
||||||
if (visible && name !== 'overview')
|
if (visible && name !== 'overview')
|
||||||
App.openWindow('closer');
|
App.openWindow('closer');
|
||||||
}
|
}
|
||||||
}]],
|
}]],
|
||||||
child: child,
|
child: child,
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
window.getChild = () => child;
|
window.getChild = () => child;
|
||||||
return window;
|
return window;
|
||||||
}
|
};
|
||||||
|
|
|
@ -3,14 +3,14 @@ const { Box } = Widget;
|
||||||
|
|
||||||
|
|
||||||
export default (size, { vertical = false } = {}) => {
|
export default (size, { vertical = false } = {}) => {
|
||||||
if (vertical) {
|
if (vertical) {
|
||||||
return Box({
|
return Box({
|
||||||
style: `min-height: ${size}px;`,
|
style: `min-height: ${size}px;`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return Box({
|
return Box({
|
||||||
style: `min-width: ${size}px;`,
|
style: `min-width: ${size}px;`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
|
@ -5,190 +5,184 @@ const { Box, Icon, Label, Button } = Widget;
|
||||||
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) {
|
||||||
let 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)) {
|
||||||
execAsync(['bash', '-c',
|
execAsync(['bash', '-c',
|
||||||
`$AGS_PATH/launch-app.sh
|
`$AGS_PATH/launch-app.sh
|
||||||
${wmClass}
|
${wmClass}
|
||||||
${app.app.get_string('Exec')}`
|
${app.app.get_string('Exec')}`,
|
||||||
]).catch(print);
|
]).catch(print);
|
||||||
|
|
||||||
globalThis.closeAll();
|
globalThis.closeAll();
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (notif.image) {
|
if (notif.image) {
|
||||||
|
return EventBox({
|
||||||
|
onPrimaryClickRelease: iconCmd,
|
||||||
|
child: Box({
|
||||||
|
valign: 'start',
|
||||||
|
hexpand: false,
|
||||||
|
className: 'icon img',
|
||||||
|
style: `background-image: url("${notif.image}");
|
||||||
|
background-size: contain;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
min-width: 78px;
|
||||||
|
min-height: 78px;`,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let icon = 'dialog-information-symbolic';
|
||||||
|
if (lookUpIcon(notif.appIcon))
|
||||||
|
icon = notif.appIcon;
|
||||||
|
|
||||||
|
|
||||||
|
if (lookUpIcon(notif.appEntry))
|
||||||
|
icon = notif.appEntry;
|
||||||
|
|
||||||
|
|
||||||
return EventBox({
|
return EventBox({
|
||||||
onPrimaryClickRelease: iconCmd,
|
onPrimaryClickRelease: iconCmd,
|
||||||
child: Box({
|
child: Box({
|
||||||
valign: 'start',
|
valign: 'start',
|
||||||
hexpand: false,
|
hexpand: false,
|
||||||
className: 'icon img',
|
className: 'icon',
|
||||||
style: `
|
style: `min-width: 78px;
|
||||||
background-image: url("${notif.image}");
|
min-height: 78px;`,
|
||||||
background-size: contain;
|
children: [Icon({
|
||||||
background-repeat: no-repeat;
|
icon, size: 58,
|
||||||
background-position: center;
|
halign: 'center',
|
||||||
min-width: 78px;
|
hexpand: true,
|
||||||
min-height: 78px;
|
valign: 'center',
|
||||||
`,
|
vexpand: true,
|
||||||
}),
|
})],
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
let icon = 'dialog-information-symbolic';
|
|
||||||
if (lookUpIcon(notif.appIcon)) {
|
|
||||||
icon = notif.appIcon;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lookUpIcon(notif.appEntry)) {
|
|
||||||
icon = notif.appEntry;
|
|
||||||
}
|
|
||||||
|
|
||||||
return EventBox({
|
|
||||||
onPrimaryClickRelease: iconCmd,
|
|
||||||
child: Box({
|
|
||||||
valign: 'start',
|
|
||||||
hexpand: false,
|
|
||||||
className: 'icon',
|
|
||||||
style: `
|
|
||||||
min-width: 78px;
|
|
||||||
min-height: 78px;
|
|
||||||
`,
|
|
||||||
children: [Icon({
|
|
||||||
icon, size: 58,
|
|
||||||
halign: 'center',
|
|
||||||
hexpand: true,
|
|
||||||
valign: 'center',
|
|
||||||
vexpand: true,
|
|
||||||
})],
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ({ notif, command = () => {}, } = {}) => {
|
export default ({ notif, command = () => {} } = {}) => {
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Gesture({
|
return Gesture({
|
||||||
maxOffset: 200,
|
maxOffset: 200,
|
||||||
command: () => command(),
|
command: () => command(),
|
||||||
properties: [
|
properties: [
|
||||||
['hovered', false],
|
['hovered', false],
|
||||||
['id', notif.id],
|
['id', notif.id],
|
||||||
],
|
],
|
||||||
onHover: w => {
|
onHover: w => {
|
||||||
if (!w._hovered) {
|
if (!w._hovered)
|
||||||
w._hovered = true;
|
w._hovered = true;
|
||||||
}
|
},
|
||||||
},
|
onHoverLost: w => {
|
||||||
onHoverLost: w => {
|
if (w._hovered)
|
||||||
if (w._hovered) {
|
w._hovered = false;
|
||||||
w._hovered = false;
|
},
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
child: Box({
|
child: Box({
|
||||||
className: `notification ${notif.urgency}`,
|
className: `notification ${notif.urgency}`,
|
||||||
vexpand: false,
|
vexpand: false,
|
||||||
// Notification
|
// Notification
|
||||||
child: Box({
|
child: Box({
|
||||||
vertical: true,
|
|
||||||
children: [
|
|
||||||
// Content
|
|
||||||
Box({
|
|
||||||
children: [
|
|
||||||
NotificationIcon(notif),
|
|
||||||
Box({
|
|
||||||
hexpand: true,
|
|
||||||
vertical: true,
|
vertical: true,
|
||||||
children: [
|
children: [
|
||||||
// Top of Content
|
// Content
|
||||||
Box({
|
Box({
|
||||||
children: [
|
children: [
|
||||||
Label({
|
NotificationIcon(notif),
|
||||||
className: 'title',
|
Box({
|
||||||
xalign: 0,
|
hexpand: true,
|
||||||
justification: 'left',
|
vertical: true,
|
||||||
hexpand: true,
|
children: [
|
||||||
maxWidthChars: 24,
|
// Top of Content
|
||||||
truncate: 'end',
|
Box({
|
||||||
wrap: true,
|
children: [
|
||||||
label: notif.summary,
|
Label({
|
||||||
useMarkup: notif.summary.startsWith('<'),
|
className: 'title',
|
||||||
}),
|
xalign: 0,
|
||||||
Label({
|
justification: 'left',
|
||||||
className: 'time',
|
hexpand: true,
|
||||||
valign: 'start',
|
maxWidthChars: 24,
|
||||||
label: setTime(notif.time),
|
truncate: 'end',
|
||||||
}),
|
wrap: true,
|
||||||
EventBox({
|
label: notif.summary,
|
||||||
reset: false,
|
useMarkup: notif.summary.startsWith('<'),
|
||||||
child: Button({
|
}),
|
||||||
className: 'close-button',
|
Label({
|
||||||
valign: 'start',
|
className: 'time',
|
||||||
onClicked: () => notif.close(),
|
valign: 'start',
|
||||||
child: Icon('window-close-symbolic'),
|
label: setTime(notif.time),
|
||||||
}),
|
}),
|
||||||
}),
|
EventBox({
|
||||||
],
|
reset: false,
|
||||||
}),
|
child: Button({
|
||||||
Label({
|
className: 'close-button',
|
||||||
className: 'description',
|
valign: 'start',
|
||||||
hexpand: true,
|
onClicked: () => notif.close(),
|
||||||
useMarkup: true,
|
child: Icon('window-close-symbolic'),
|
||||||
xalign: 0,
|
}),
|
||||||
justification: 'left',
|
}),
|
||||||
label: notif.body,
|
],
|
||||||
wrap: true,
|
}),
|
||||||
}),
|
Label({
|
||||||
|
className: 'description',
|
||||||
|
hexpand: true,
|
||||||
|
useMarkup: true,
|
||||||
|
xalign: 0,
|
||||||
|
justification: 'left',
|
||||||
|
label: notif.body,
|
||||||
|
wrap: true,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
// Actions
|
||||||
|
Box({
|
||||||
|
className: 'actions',
|
||||||
|
children: notif.actions.map(action => Button({
|
||||||
|
className: 'action-button',
|
||||||
|
onClicked: () => notif.invoke(action.id),
|
||||||
|
hexpand: true,
|
||||||
|
child: Label(action.label),
|
||||||
|
})),
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
],
|
}),
|
||||||
}),
|
});
|
||||||
// Actions
|
|
||||||
Box({
|
|
||||||
className: 'actions',
|
|
||||||
children: notif.actions.map(action => Button({
|
|
||||||
className: 'action-button',
|
|
||||||
onClicked: () => notif.invoke(action.id),
|
|
||||||
hexpand: true,
|
|
||||||
child: Label(action.label),
|
|
||||||
})),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,148 +8,147 @@ import EventBox from '../misc/cursorbox.js';
|
||||||
|
|
||||||
|
|
||||||
const ClearButton = () => EventBox({
|
const ClearButton = () => EventBox({
|
||||||
child: Button({
|
child: Button({
|
||||||
onPrimaryClickRelease: button => {
|
onPrimaryClickRelease: button => {
|
||||||
button._popups.children.forEach(ch => {
|
button._popups.children.forEach(ch => {
|
||||||
ch.child.setStyle(ch.child._leftAnim1);
|
ch.child.setStyle(ch.child._leftAnim1);
|
||||||
});
|
});
|
||||||
|
|
||||||
button._notifList.children.forEach(ch => {
|
button._notifList.children.forEach(ch => {
|
||||||
if (ch.child)
|
if (ch.child)
|
||||||
ch.child.setStyle(ch.child._rightAnim1);
|
ch.child.setStyle(ch.child._rightAnim1);
|
||||||
timeout(500, () => {
|
timeout(500, () => {
|
||||||
button._notifList.remove(ch);
|
button._notifList.remove(ch);
|
||||||
Notifications.clear();
|
Notifications.clear();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
properties: [
|
properties: [
|
||||||
['notifList'],
|
['notifList'],
|
||||||
['popups'],
|
['popups'],
|
||||||
],
|
],
|
||||||
connections: [[Notifications, button => {
|
connections: [[Notifications, button => {
|
||||||
if (!button._notifList)
|
if (!button._notifList)
|
||||||
button._notifList = NotificationList;
|
button._notifList = NotificationList;
|
||||||
|
|
||||||
if (!button._popups)
|
if (!button._popups)
|
||||||
button._popups = App.getWindow('notifications').child.children[0].child;
|
button._popups = App.getWindow('notifications').child.children[0].child;
|
||||||
|
|
||||||
button.sensitive = Notifications.notifications.length > 0;
|
button.sensitive = Notifications.notifications.length > 0;
|
||||||
}]],
|
}]],
|
||||||
child: Box({
|
child: Box({
|
||||||
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';
|
||||||
}]],
|
}]],
|
||||||
|
}),
|
||||||
|
],
|
||||||
}),
|
}),
|
||||||
],
|
|
||||||
}),
|
}),
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const Header = () => Box({
|
const Header = () => Box({
|
||||||
className: 'header',
|
className: 'header',
|
||||||
children: [
|
children: [
|
||||||
Label({
|
Label({
|
||||||
label: 'Notifications',
|
label: 'Notifications',
|
||||||
hexpand: true,
|
hexpand: true,
|
||||||
xalign: 0,
|
xalign: 0,
|
||||||
}),
|
}),
|
||||||
ClearButton(),
|
ClearButton(),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
const NotificationList = Box({
|
const NotificationList = Box({
|
||||||
vertical: true,
|
vertical: true,
|
||||||
vexpand: true,
|
vexpand: true,
|
||||||
connections: [
|
connections: [
|
||||||
[Notifications, (box, id) => {
|
[Notifications, (box, id) => {
|
||||||
if (box.children.length == 0) {
|
if (box.children.length == 0) {
|
||||||
box.children = Notifications.notifications
|
box.children = Notifications.notifications
|
||||||
.reverse()
|
.reverse()
|
||||||
.map(n => Notification({ notif: n, command: () => n.close() }));
|
.map(n => Notification({ notif: n, command: () => n.close() }));
|
||||||
}
|
}
|
||||||
else if (id) {
|
else if (id) {
|
||||||
let notif = Notifications.getNotification(id);
|
const notif = Notifications.getNotification(id);
|
||||||
|
|
||||||
const NewNotif = Notification({
|
const NewNotif = Notification({
|
||||||
notif,
|
notif,
|
||||||
command: () => notif.close(),
|
command: () => notif.close(),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (NewNotif) {
|
if (NewNotif) {
|
||||||
box.add(NewNotif);
|
box.add(NewNotif);
|
||||||
box.show_all();
|
box.show_all();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}, 'notified'],
|
||||||
|
|
||||||
}, 'notified'],
|
[Notifications, (box, id) => {
|
||||||
|
for (const ch of box.children) {
|
||||||
|
if (ch._id == id) {
|
||||||
|
ch.child.setStyle(ch.child._rightAnim1);
|
||||||
|
timeout(500, () => box.remove(ch));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 'closed'],
|
||||||
|
|
||||||
[Notifications, (box, id) => {
|
[Notifications, box => box.visible = Notifications.notifications.length > 0],
|
||||||
for (const ch of box.children) {
|
],
|
||||||
if (ch._id == id) {
|
|
||||||
ch.child.setStyle(ch.child._rightAnim1);
|
|
||||||
timeout(500, () => box.remove(ch));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, 'closed'],
|
|
||||||
|
|
||||||
[Notifications, box => box.visible = Notifications.notifications.length > 0],
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const Placeholder = () => Revealer({
|
const Placeholder = () => Revealer({
|
||||||
transition: 'crossfade',
|
transition: 'crossfade',
|
||||||
connections: [[Notifications, box => {
|
connections: [[Notifications, box => {
|
||||||
box.revealChild = Notifications.notifications.length === 0;
|
box.revealChild = Notifications.notifications.length === 0;
|
||||||
}]],
|
}]],
|
||||||
child: Box({
|
child: Box({
|
||||||
className: 'placeholder',
|
className: 'placeholder',
|
||||||
vertical: true,
|
vertical: true,
|
||||||
valign: 'center',
|
valign: 'center',
|
||||||
halign: 'center',
|
halign: 'center',
|
||||||
vexpand: true,
|
vexpand: true,
|
||||||
hexpand: true,
|
hexpand: true,
|
||||||
children: [
|
children: [
|
||||||
Icon('notification-disabled-symbolic'),
|
Icon('notification-disabled-symbolic'),
|
||||||
Label('Your inbox is empty'),
|
Label('Your inbox is empty'),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const NotificationCenterWidget = () => Box({
|
const NotificationCenterWidget = () => Box({
|
||||||
className: 'notification-center',
|
className: 'notification-center',
|
||||||
vertical: true,
|
vertical: true,
|
||||||
children: [
|
children: [
|
||||||
Header(),
|
Header(),
|
||||||
Box({
|
Box({
|
||||||
className: 'notification-wallpaper-box',
|
className: 'notification-wallpaper-box',
|
||||||
children: [
|
|
||||||
Scrollable({
|
|
||||||
className: 'notification-list-box',
|
|
||||||
hscroll: 'never',
|
|
||||||
vscroll: 'automatic',
|
|
||||||
child: Box({
|
|
||||||
className: 'notification-list',
|
|
||||||
vertical: true,
|
|
||||||
children: [
|
children: [
|
||||||
NotificationList,
|
Scrollable({
|
||||||
Placeholder(),
|
className: 'notification-list-box',
|
||||||
|
hscroll: 'never',
|
||||||
|
vscroll: 'automatic',
|
||||||
|
child: Box({
|
||||||
|
className: 'notification-list',
|
||||||
|
vertical: true,
|
||||||
|
children: [
|
||||||
|
NotificationList,
|
||||||
|
Placeholder(),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
})
|
],
|
||||||
],
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default () => PopupWindow({
|
export default () => PopupWindow({
|
||||||
name: 'notification-center',
|
name: 'notification-center',
|
||||||
anchor: [ 'top', 'right' ],
|
anchor: ['top', 'right'],
|
||||||
margin: [ 8, 60, 0, 0 ],
|
margin: [8, 60, 0, 0],
|
||||||
child: NotificationCenterWidget(),
|
child: NotificationCenterWidget(),
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Widget } from '../../imports.js';
|
import { Utils, Widget } from '../../imports.js';
|
||||||
const { Box, EventBox } = Widget;
|
const { Box, EventBox } = Widget;
|
||||||
|
|
||||||
import Gtk from 'gi://Gtk';
|
import Gtk from 'gi://Gtk';
|
||||||
|
@ -7,136 +7,136 @@ const display = Gdk.Display.get_default();
|
||||||
|
|
||||||
|
|
||||||
export default ({
|
export default ({
|
||||||
maxOffset = 150,
|
maxOffset = 150,
|
||||||
startMargin = 0,
|
startMargin = 0,
|
||||||
endMargin = 300,
|
endMargin = 300,
|
||||||
command = () => {},
|
command = () => {},
|
||||||
onHover = w => {},
|
onHover = () => {},
|
||||||
onHoverLost = w => {},
|
onHoverLost = () => {},
|
||||||
child = '',
|
child = '',
|
||||||
children = [],
|
children = [],
|
||||||
properties = [[]],
|
properties = [[]],
|
||||||
...props
|
...props
|
||||||
}) => {
|
}) => {
|
||||||
let widget = EventBox({
|
const widget = EventBox({
|
||||||
...props,
|
...props,
|
||||||
properties: [
|
properties: [
|
||||||
['dragging', false],
|
['dragging', false],
|
||||||
...properties,
|
...properties,
|
||||||
],
|
],
|
||||||
onHover: self => {
|
onHover: self => {
|
||||||
self.window.set_cursor(Gdk.Cursor.new_from_name(display, 'grab'));
|
self.window.set_cursor(Gdk.Cursor.new_from_name(display, 'grab'));
|
||||||
onHover(self);
|
onHover(self);
|
||||||
},
|
},
|
||||||
onHoverLost: self => {
|
onHoverLost: self => {
|
||||||
self.window.set_cursor(null);
|
self.window.set_cursor(null);
|
||||||
onHoverLost(self);
|
onHoverLost(self);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
let gesture = Gtk.GestureDrag.new(widget);
|
const gesture = Gtk.GestureDrag.new(widget);
|
||||||
|
|
||||||
let leftAnim1 = `transition: margin 0.5s ease, opacity 0.5s ease;
|
const leftAnim1 = `transition: margin 0.5s ease, opacity 0.5s ease;
|
||||||
margin-left: -${Number(maxOffset + endMargin)}px;
|
margin-left: -${Number(maxOffset + endMargin)}px;
|
||||||
margin-right: ${Number(maxOffset + endMargin)}px;
|
margin-right: ${Number(maxOffset + endMargin)}px;
|
||||||
opacity: 0;`;
|
opacity: 0;`;
|
||||||
|
|
||||||
let leftAnim2 = `transition: margin 0.5s ease, opacity 0.5s ease;
|
const leftAnim2 = `transition: margin 0.5s ease, opacity 0.5s ease;
|
||||||
margin-left: -${Number(maxOffset + endMargin)}px;
|
margin-left: -${Number(maxOffset + endMargin)}px;
|
||||||
margin-right: ${Number(maxOffset + endMargin)}px;
|
margin-right: ${Number(maxOffset + endMargin)}px;
|
||||||
margin-bottom: -70px; margin-top: -70px; opacity: 0;`;
|
margin-bottom: -70px; margin-top: -70px; opacity: 0;`;
|
||||||
|
|
||||||
let rightAnim1 = `transition: margin 0.5s ease, opacity 0.5s ease;
|
const rightAnim1 = `transition: margin 0.5s ease, opacity 0.5s ease;
|
||||||
margin-left: ${Number(maxOffset + endMargin)}px;
|
margin-left: ${Number(maxOffset + endMargin)}px;
|
||||||
margin-right: -${Number(maxOffset + endMargin)}px;
|
margin-right: -${Number(maxOffset + endMargin)}px;
|
||||||
opacity: 0;`;
|
opacity: 0;`;
|
||||||
|
|
||||||
let rightAnim2 = `transition: margin 0.5s ease, opacity 0.5s ease;
|
const rightAnim2 = `transition: margin 0.5s ease, opacity 0.5s ease;
|
||||||
margin-left: ${Number(maxOffset + endMargin)}px;
|
margin-left: ${Number(maxOffset + endMargin)}px;
|
||||||
margin-right: -${Number(maxOffset + endMargin)}px;
|
margin-right: -${Number(maxOffset + endMargin)}px;
|
||||||
margin-bottom: -70px; margin-top: -70px; opacity: 0;`;
|
margin-bottom: -70px; margin-top: -70px; opacity: 0;`;
|
||||||
|
|
||||||
widget.add(Box({
|
widget.add(Box({
|
||||||
properties: [
|
properties: [
|
||||||
['leftAnim1', leftAnim1],
|
['leftAnim1', leftAnim1],
|
||||||
['leftAnim2', leftAnim2],
|
['leftAnim2', leftAnim2],
|
||||||
['rightAnim1', rightAnim1],
|
['rightAnim1', rightAnim1],
|
||||||
['rightAnim2', rightAnim2],
|
['rightAnim2', rightAnim2],
|
||||||
['ready', false]
|
['ready', false],
|
||||||
],
|
],
|
||||||
children: [
|
children: [
|
||||||
...children,
|
...children,
|
||||||
child,
|
child,
|
||||||
],
|
],
|
||||||
style: leftAnim2,
|
style: leftAnim2,
|
||||||
connections: [
|
connections: [
|
||||||
|
|
||||||
[gesture, self => {
|
[gesture, self => {
|
||||||
var offset = gesture.get_offset()[1];
|
var offset = gesture.get_offset()[1];
|
||||||
|
|
||||||
if (offset >= 0) {
|
if (offset >= 0) {
|
||||||
self.setStyle(`margin-left: ${Number(offset + startMargin)}px;
|
self.setStyle(`margin-left: ${Number(offset + startMargin)}px;
|
||||||
margin-right: -${Number(offset + startMargin)}px;`);
|
margin-right: -${Number(offset + startMargin)}px;`);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
offset = Math.abs(offset);
|
offset = Math.abs(offset);
|
||||||
self.setStyle(`margin-right: ${Number(offset + startMargin)}px;
|
self.setStyle(`margin-right: ${Number(offset + startMargin)}px;
|
||||||
margin-left: -${Number(offset + startMargin)}px;`);
|
margin-left: -${Number(offset + startMargin)}px;`);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.get_parent()._dragging = Math.abs(offset) > 10;
|
self.get_parent()._dragging = Math.abs(offset) > 10;
|
||||||
|
|
||||||
if (widget.window)
|
if (widget.window)
|
||||||
widget.window.set_cursor(Gdk.Cursor.new_from_name(display, 'grabbing'));
|
widget.window.set_cursor(Gdk.Cursor.new_from_name(display, 'grabbing'));
|
||||||
}, 'drag-update'],
|
}, 'drag-update'],
|
||||||
|
|
||||||
[gesture, self => {
|
[gesture, self => {
|
||||||
if (!self._ready) {
|
if (!self._ready) {
|
||||||
self.setStyle(`transition: margin 0.5s ease, opacity 0.5s ease;
|
self.setStyle(`transition: margin 0.5s ease, opacity 0.5s ease;
|
||||||
margin-left: -${Number(maxOffset + endMargin)}px;
|
margin-left: -${Number(maxOffset + endMargin)}px;
|
||||||
margin-right: ${Number(maxOffset + endMargin)}px;
|
margin-right: ${Number(maxOffset + endMargin)}px;
|
||||||
margin-bottom: 0px; margin-top: 0px; opacity: 0;`);
|
margin-bottom: 0px; margin-top: 0px; opacity: 0;`);
|
||||||
|
|
||||||
setTimeout(() => {
|
Utils.timeout(500, () => {
|
||||||
self.setStyle(`transition: margin 0.5s ease, opacity 0.5s ease;
|
self.setStyle(`transition: margin 0.5s ease, opacity 0.5s ease;
|
||||||
margin-left: ${startMargin}px;
|
margin-left: ${startMargin}px;
|
||||||
margin-right: ${startMargin}px;
|
margin-right: ${startMargin}px;
|
||||||
margin-bottom: unset; margin-top: unset; opacity: 1;`);
|
margin-bottom: unset; margin-top: unset; opacity: 1;`);
|
||||||
}, 500);
|
});
|
||||||
setTimeout(() => self._ready = true, 1000);
|
Utils.timeout(1000, () => self._ready = true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const offset = gesture.get_offset()[1];
|
const offset = gesture.get_offset()[1];
|
||||||
|
|
||||||
if (Math.abs(offset) > maxOffset) {
|
if (Math.abs(offset) > maxOffset) {
|
||||||
if (offset > 0) {
|
if (offset > 0) {
|
||||||
self.setStyle(rightAnim1);
|
self.setStyle(rightAnim1);
|
||||||
setTimeout(() => self.setStyle(rightAnim2), 500);
|
Utils.timeout(500, () => self.setStyle(rightAnim2));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
self.setStyle(leftAnim1);
|
self.setStyle(leftAnim1);
|
||||||
setTimeout(() => self.setStyle(leftAnim2), 500);
|
Utils.timeout(500, () => self.setStyle(leftAnim2));
|
||||||
}
|
}
|
||||||
setTimeout(() => {
|
Utils.timeout(1000, () => {
|
||||||
command();
|
command();
|
||||||
self.destroy();
|
self.destroy();
|
||||||
}, 1000);
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
self.setStyle(`transition: margin 0.5s ease, opacity 0.5s ease;
|
self.setStyle(`transition: margin 0.5s ease, opacity 0.5s ease;
|
||||||
margin-left: ${startMargin}px;
|
margin-left: ${startMargin}px;
|
||||||
margin-right: ${startMargin}px;
|
margin-right: ${startMargin}px;
|
||||||
margin-bottom: unset; margin-top: unset; opacity: 1;`);
|
margin-bottom: unset; margin-top: unset; opacity: 1;`);
|
||||||
if (widget.window)
|
if (widget.window)
|
||||||
widget.window.set_cursor(Gdk.Cursor.new_from_name(display, 'grab'));
|
widget.window.set_cursor(Gdk.Cursor.new_from_name(display, 'grab'));
|
||||||
|
|
||||||
self.get_parent()._dragging = false;
|
self.get_parent()._dragging = false;
|
||||||
}
|
}
|
||||||
}, 'drag-end'],
|
}, 'drag-end'],
|
||||||
|
|
||||||
],
|
],
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return widget;
|
return widget;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,87 +1,89 @@
|
||||||
import { Notifications, Widget } from '../../imports.js';
|
import { Notifications, Utils, Widget } from '../../imports.js';
|
||||||
const { Box, Revealer, Window } = Widget;
|
const { Box, Revealer, Window } = Widget;
|
||||||
|
|
||||||
|
import GLib from 'gi://GLib';
|
||||||
|
|
||||||
import Notification from './base.js';
|
import Notification from './base.js';
|
||||||
|
|
||||||
|
|
||||||
const Popups = () => Box({
|
const Popups = () => Box({
|
||||||
vertical: true,
|
vertical: true,
|
||||||
properties: [
|
properties: [
|
||||||
['map', new Map()],
|
['map', new Map()],
|
||||||
|
|
||||||
['dismiss', (box, id, force = false) => {
|
['dismiss', (box, id, force = false) => {
|
||||||
if (!id || !box._map.has(id) ||
|
if (!id || !box._map.has(id) ||
|
||||||
box._map.get(id)._hovered && !force) {
|
box._map.get(id)._hovered && !force)
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if (box._map.size - 1 === 0)
|
|
||||||
box.get_parent().reveal_child = false;
|
|
||||||
|
|
||||||
setTimeout(() => {
|
if (box._map.size - 1 === 0)
|
||||||
if (box._map.get(id)?.interval) {
|
box.get_parent().reveal_child = false;
|
||||||
box._map.get(id).interval.destroy();
|
|
||||||
box._map.get(id).interval = undefined;
|
|
||||||
}
|
|
||||||
box._map.get(id)?.destroy();
|
|
||||||
box._map.delete(id);
|
|
||||||
}, 200);
|
|
||||||
}],
|
|
||||||
|
|
||||||
['notify', (box, id) => {
|
Utils.timeout(200, () => {
|
||||||
if (!id || Notifications.dnd)
|
if (box._map.get(id)?.interval) {
|
||||||
return;
|
box._map.get(id).interval.destroy();
|
||||||
|
box._map.get(id).interval = undefined;
|
||||||
|
}
|
||||||
|
box._map.get(id)?.destroy();
|
||||||
|
box._map.delete(id);
|
||||||
|
});
|
||||||
|
}],
|
||||||
|
|
||||||
if (! Notifications.getNotification(id))
|
['notify', (box, id) => {
|
||||||
return;
|
if (!id || Notifications.dnd)
|
||||||
|
return;
|
||||||
|
|
||||||
box._map.delete(id);
|
if (! Notifications.getNotification(id))
|
||||||
|
return;
|
||||||
|
|
||||||
let notif = Notifications.getNotification(id);
|
box._map.delete(id);
|
||||||
box._map.set(id, Notification({
|
|
||||||
notif,
|
|
||||||
command: () => notif.dismiss(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
box.children = Array.from(box._map.values()).reverse();
|
const notif = Notifications.getNotification(id);
|
||||||
|
box._map.set(id, Notification({
|
||||||
|
notif,
|
||||||
|
command: () => notif.dismiss(),
|
||||||
|
}));
|
||||||
|
|
||||||
setTimeout(() => {
|
box.children = Array.from(box._map.values()).reverse();
|
||||||
box.get_parent().revealChild = true;
|
|
||||||
}, 10);
|
|
||||||
|
|
||||||
box._map.get(id).interval = setInterval(() => {
|
Utils.timeout(10, () => {
|
||||||
if (!box._map.get(id)._hovered) {
|
box.get_parent().revealChild = true;
|
||||||
box._map.get(id).child.setStyle(box._map.get(id).child._leftAnim1);
|
});
|
||||||
|
|
||||||
if (box._map.get(id).interval) {
|
box._map.get(id).interval = Utils.interval(4500, () => {
|
||||||
box._map.get(id).interval.destroy();
|
if (!box._map.get(id)._hovered) {
|
||||||
box._map.get(id).interval = undefined;
|
box._map.get(id).child.setStyle(box._map.get(id).child._leftAnim1);
|
||||||
}
|
|
||||||
}
|
if (box._map.get(id).interval) {
|
||||||
}, 4500);
|
GLib.source_remove(box._map.get(id).interval);
|
||||||
}],
|
box._map.get(id).interval = undefined;
|
||||||
],
|
}
|
||||||
connections: [
|
}
|
||||||
[Notifications, (box, id) => box._notify(box, id), 'notified'],
|
});
|
||||||
[Notifications, (box, id) => box._dismiss(box, id), 'dismissed'],
|
}],
|
||||||
[Notifications, (box, id) => box._dismiss(box, id, true), 'closed'],
|
],
|
||||||
],
|
connections: [
|
||||||
|
[Notifications, (box, id) => box._notify(box, id), 'notified'],
|
||||||
|
[Notifications, (box, id) => box._dismiss(box, id), 'dismissed'],
|
||||||
|
[Notifications, (box, id) => box._dismiss(box, id, true), 'closed'],
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
const PopupList = ({ transition = 'none' } = {}) => Box({
|
const PopupList = ({ transition = 'none' } = {}) => Box({
|
||||||
className: 'notifications-popup-list',
|
className: 'notifications-popup-list',
|
||||||
style: 'padding: 1px',
|
style: 'padding: 1px',
|
||||||
children: [
|
children: [
|
||||||
Revealer({
|
Revealer({
|
||||||
transition,
|
transition,
|
||||||
child: Popups(),
|
child: Popups(),
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
export default () => Window({
|
export default () => Window({
|
||||||
name: `notifications`,
|
name: 'notifications',
|
||||||
anchor: [ 'top', 'left' ],
|
anchor: ['top', 'left'],
|
||||||
child: PopupList(),
|
child: PopupList(),
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,11 +6,11 @@ import { WindowButton } from './dragndrop.js';
|
||||||
import * as VARS from './variables.js';
|
import * as VARS from './variables.js';
|
||||||
|
|
||||||
// Has to be a traditional function for 'this' scope
|
// Has to be a traditional function for 'this' scope
|
||||||
Array.prototype.remove = function (el) { this.splice(this.indexOf(el), 1) };
|
Array.prototype.remove = function (el) { this.splice(this.indexOf(el), 1); };
|
||||||
|
|
||||||
const scale = size => size * VARS.SCALE - VARS.MARGIN;
|
const scale = size => size * VARS.SCALE - VARS.MARGIN;
|
||||||
const getFontSize = client => Math.min(scale(client.size[0]),
|
const getFontSize = client => Math.min(scale(client.size[0]),
|
||||||
scale(client.size[1])) * VARS.ICON_SCALE;
|
scale(client.size[1])) * VARS.ICON_SCALE;
|
||||||
|
|
||||||
const IconStyle = client => `transition: font-size 0.2s linear;
|
const IconStyle = client => `transition: font-size 0.2s linear;
|
||||||
min-width: ${scale(client.size[0])}px;
|
min-width: ${scale(client.size[0])}px;
|
||||||
|
@ -19,127 +19,128 @@ const IconStyle = client => `transition: font-size 0.2s linear;
|
||||||
|
|
||||||
|
|
||||||
const Client = (client, active, clients) => {
|
const Client = (client, active, clients) => {
|
||||||
let wsName = String(client.workspace.name).replace('special:', '');
|
const wsName = String(client.workspace.name).replace('special:', '');
|
||||||
let wsId = client.workspace.id;
|
const wsId = client.workspace.id;
|
||||||
let addr = `address:${client.address}`;
|
const addr = `address:${client.address}`;
|
||||||
|
|
||||||
// FIXME: special workspaces not closing when in one and clicking on normal client
|
// FIXME: special workspaces not closing when in one and clicking on normal client
|
||||||
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({
|
||||||
address: client.address,
|
address: client.address,
|
||||||
onSecondaryClickRelease: () => {
|
onSecondaryClickRelease: () => {
|
||||||
execAsync(`hyprctl dispatch closewindow ${addr}`)
|
execAsync(`hyprctl dispatch closewindow ${addr}`)
|
||||||
.catch(print);
|
.catch(print);
|
||||||
},
|
},
|
||||||
|
|
||||||
onPrimaryClickRelease: () => {
|
onPrimaryClickRelease: () => {
|
||||||
if (wsId < 0) {
|
if (wsId < 0) {
|
||||||
if (client.workspace.name === 'special') {
|
if (client.workspace.name === 'special') {
|
||||||
execAsync(`hyprctl dispatch
|
execAsync(`hyprctl dispatch
|
||||||
movetoworkspacesilent special:${wsId},${addr}`)
|
movetoworkspacesilent special:${wsId},${addr}`)
|
||||||
.then(
|
.then(
|
||||||
|
|
||||||
execAsync(`hyprctl dispatch togglespecialworkspace ${wsId}`).then(
|
execAsync(`hyprctl dispatch togglespecialworkspace ${wsId}`).then(
|
||||||
() => App.closeWindow('overview')
|
() => App.closeWindow('overview'),
|
||||||
).catch(print)
|
).catch(print),
|
||||||
|
|
||||||
).catch(print);
|
).catch(print);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
execAsync(`hyprctl dispatch togglespecialworkspace ${wsName}`).then(
|
execAsync(`hyprctl 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
|
||||||
let activeAddress = Hyprland.active.client.address;
|
const activeAddress = Hyprland.active.client.address;
|
||||||
let currentActive = clients.find(c => c.address === activeAddress)
|
const currentActive = clients.find(c => c.address === activeAddress);
|
||||||
|
|
||||||
if (currentActive && currentActive.workspace.id < 0) {
|
if (currentActive && currentActive.workspace.id < 0) {
|
||||||
execAsync(`hyprctl dispatch togglespecialworkspace ${wsName}`)
|
execAsync(`hyprctl dispatch togglespecialworkspace ${wsName}`)
|
||||||
.catch(print);
|
.catch(print);
|
||||||
}
|
}
|
||||||
execAsync(`hyprctl dispatch focuswindow ${addr}`).then(
|
execAsync(`hyprctl dispatch focuswindow ${addr}`).then(
|
||||||
() => App.closeWindow('overview')
|
() => App.closeWindow('overview'),
|
||||||
).catch(print);
|
).catch(print);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
child: Icon({
|
child: Icon({
|
||||||
className: `window ${active}`,
|
className: `window ${active}`,
|
||||||
style: IconStyle(client) + 'font-size: 10px;',
|
style: IconStyle(client) + 'font-size: 10px;',
|
||||||
icon: client.class,
|
icon: client.class,
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export function updateClients(box) {
|
export function updateClients(box) {
|
||||||
execAsync('hyprctl clients -j').then(out => {
|
execAsync('hyprctl clients -j').then(out => {
|
||||||
let 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 => {
|
||||||
let fixed = workspace.getFixed();
|
const fixed = workspace.getFixed();
|
||||||
let 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
|
|
||||||
client.at[1] -= 2920;
|
|
||||||
|
|
||||||
// Special workspaces that haven't been opened yet
|
// TODO: fix multi monitor issue. this is just a temp fix
|
||||||
// return a size of 0. We need to set them to default
|
client.at[1] -= 2920;
|
||||||
// values to show the workspace properly
|
|
||||||
if (client.size[0] === 0) {
|
|
||||||
client.size[0] = VARS.DEFAULT_SPECIAL.SIZE_X;
|
|
||||||
client.size[1] = VARS.DEFAULT_SPECIAL.SIZE_Y;
|
|
||||||
client.at[0] = VARS.DEFAULT_SPECIAL.POS_X;
|
|
||||||
client.at[1] = VARS.DEFAULT_SPECIAL.POS_Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
let newClient = [
|
// Special workspaces that haven't been opened yet
|
||||||
fixed.get_children().find(ch => ch._address == client.address),
|
// return a size of 0. We need to set them to default
|
||||||
client.at[0] * VARS.SCALE,
|
// values to show the workspace properly
|
||||||
client.at[1] * VARS.SCALE,
|
if (client.size[0] === 0) {
|
||||||
];
|
client.size[0] = VARS.DEFAULT_SPECIAL.SIZE_X;
|
||||||
|
client.size[1] = VARS.DEFAULT_SPECIAL.SIZE_Y;
|
||||||
|
client.at[0] = VARS.DEFAULT_SPECIAL.POS_X;
|
||||||
|
client.at[1] = VARS.DEFAULT_SPECIAL.POS_Y;
|
||||||
|
}
|
||||||
|
|
||||||
if (newClient[0]) {
|
const newClient = [
|
||||||
toRemove.remove(newClient[0]);
|
fixed.get_children().find(ch => ch._address == client.address),
|
||||||
fixed.move(...newClient);
|
client.at[0] * VARS.SCALE,
|
||||||
}
|
client.at[1] * VARS.SCALE,
|
||||||
else {
|
];
|
||||||
newClient[0] = Client(client, active, clients);
|
|
||||||
fixed.put(...newClient);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set a timeout here to have an animation when the icon first appears
|
if (newClient[0]) {
|
||||||
setTimeout(() => {
|
toRemove.remove(newClient[0]);
|
||||||
newClient[0].child.child.className = `window ${active}`;
|
fixed.move(...newClient);
|
||||||
newClient[0].child.child.style = IconStyle(client);
|
}
|
||||||
}, 1);
|
else {
|
||||||
});
|
newClient[0] = Client(client, active, clients);
|
||||||
fixed.show_all();
|
fixed.put(...newClient);
|
||||||
toRemove.forEach(ch => {
|
}
|
||||||
if (ch._toDestroy) {
|
|
||||||
ch.destroy();
|
// Set a timeout here to have an animation when the icon first appears
|
||||||
}
|
Utils.timeout(1, () => {
|
||||||
else {
|
newClient[0].child.child.className = `window ${active}`;
|
||||||
ch.revealChild = false;
|
newClient[0].child.child.style = IconStyle(client);
|
||||||
ch._toDestroy = true;
|
});
|
||||||
}
|
});
|
||||||
});
|
|
||||||
});
|
fixed.show_all();
|
||||||
}).catch(print);
|
toRemove.forEach(ch => {
|
||||||
};
|
if (ch._toDestroy) {
|
||||||
|
ch.destroy();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ch.revealChild = false;
|
||||||
|
ch._toDestroy = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}).catch(print);
|
||||||
|
}
|
||||||
|
|
|
@ -13,61 +13,61 @@ const TARGET = [Gtk.TargetEntry.new('text/plain', Gtk.TargetFlags.SAME_APP, 0)];
|
||||||
|
|
||||||
|
|
||||||
function createSurfaceFromWidget(widget) {
|
function 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,
|
||||||
alloc.width,
|
alloc.width,
|
||||||
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';
|
||||||
}
|
|
||||||
execAsync(`hyprctl dispatch movetoworkspacesilent ${id},address:${data.get_text()}`)
|
execAsync(`hyprctl 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);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const WindowButton = ({address, ...props} = {}) => Button({
|
export const WindowButton = ({ address, ...props } = {}) => Button({
|
||||||
type: "Button",
|
type: 'Button',
|
||||||
...props,
|
...props,
|
||||||
setup: self => {
|
setup: self => {
|
||||||
self.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, TARGET, Gdk.DragAction.COPY);
|
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();
|
||||||
|
|
||||||
let mainBox = App.getWindow('overview').getChild();
|
const mainBox = App.getWindow('overview').getChild();
|
||||||
updateClients(mainBox);
|
updateClients(mainBox);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,42 +7,42 @@ import { updateClients } from './clients.js';
|
||||||
|
|
||||||
|
|
||||||
function update(box) {
|
function update(box) {
|
||||||
getWorkspaces(box);
|
getWorkspaces(box);
|
||||||
updateWorkspaces(box);
|
updateWorkspaces(box);
|
||||||
updateClients(box);
|
updateClients(box);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default () => PopupWindow({
|
export default () => PopupWindow({
|
||||||
name: 'overview',
|
name: 'overview',
|
||||||
transition: 'crossfade',
|
transition: 'crossfade',
|
||||||
onOpen: child => update(child),
|
onOpen: child => update(child),
|
||||||
|
|
||||||
child: Box({
|
child: Box({
|
||||||
className: 'overview',
|
className: 'overview',
|
||||||
vertical: true,
|
|
||||||
children: [
|
|
||||||
Box({
|
|
||||||
vertical: true,
|
vertical: true,
|
||||||
children: [
|
children: [
|
||||||
WorkspaceRow('normal', 0),
|
Box({
|
||||||
|
vertical: true,
|
||||||
|
children: [
|
||||||
|
WorkspaceRow('normal', 0),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
Box({
|
||||||
|
vertical: true,
|
||||||
|
children: [
|
||||||
|
WorkspaceRow('special', 0),
|
||||||
|
],
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
}),
|
connections: [[Hyprland, self => {
|
||||||
Box({
|
if (!App.getWindow('overview').visible)
|
||||||
vertical: true,
|
return;
|
||||||
children: [
|
|
||||||
WorkspaceRow('special', 0),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
connections: [[Hyprland, self => {
|
|
||||||
if (!App.getWindow('overview').visible)
|
|
||||||
return;
|
|
||||||
|
|
||||||
update(self);
|
update(self);
|
||||||
}]],
|
}]],
|
||||||
properties: [
|
properties: [
|
||||||
['workspaces'],
|
['workspaces'],
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,13 +2,13 @@ export const SCALE = 0.11;
|
||||||
export const ICON_SCALE = 0.8;
|
export const ICON_SCALE = 0.8;
|
||||||
export const MARGIN = 8;
|
export const MARGIN = 8;
|
||||||
export const DEFAULT_SPECIAL = {
|
export const DEFAULT_SPECIAL = {
|
||||||
SIZE_X: 1524,
|
SIZE_X: 1524,
|
||||||
SIZE_Y: 908,
|
SIZE_Y: 908,
|
||||||
POS_X: 197,
|
POS_X: 197,
|
||||||
POS_Y: 170,
|
POS_Y: 170,
|
||||||
};
|
};
|
||||||
export const WORKSPACE_PER_ROW = 6;
|
export const WORKSPACE_PER_ROW = 6;
|
||||||
export const SCREEN = {
|
export const SCREEN = {
|
||||||
X: 1920,
|
X: 1920,
|
||||||
Y: 1200,
|
Y: 1200,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import { Hyprland, Widget } from '../../imports.js';
|
import { Hyprland, Utils, Widget } from '../../imports.js';
|
||||||
const { Revealer, CenterBox, Box, EventBox, Label, Overlay } = Widget;
|
const { Revealer, CenterBox, Box, EventBox, Label, Overlay } = Widget;
|
||||||
|
|
||||||
import Gtk from 'gi://Gtk';
|
import Gtk from 'gi://Gtk';
|
||||||
|
import GLib from 'gi://GLib';
|
||||||
|
|
||||||
import { WorkspaceDrop } from './dragndrop.js';
|
import { WorkspaceDrop } from './dragndrop.js';
|
||||||
import * as VARS from './variables.js';
|
import * as VARS from './variables.js';
|
||||||
|
@ -11,203 +12,201 @@ const DEFAULT_STYLE = `min-width: ${VARS.SCREEN.X * VARS.SCALE}px;
|
||||||
|
|
||||||
|
|
||||||
export function getWorkspaces(box) {
|
export function getWorkspaces(box) {
|
||||||
let children = [];
|
const children = [];
|
||||||
box.children.forEach(type => {
|
box.children.forEach(type => {
|
||||||
type.children.forEach(row => {
|
type.children.forEach(row => {
|
||||||
row.child.centerWidget.child.children.forEach(ch => {
|
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({
|
export const WorkspaceRow = (className, i) => Revealer({
|
||||||
transition: 'slide_down',
|
transition: 'slide_down',
|
||||||
connections: [[Hyprland, rev => {
|
connections: [[Hyprland, rev => {
|
||||||
let minId = i * VARS.WORKSPACE_PER_ROW;
|
const minId = i * VARS.WORKSPACE_PER_ROW;
|
||||||
let activeId = Hyprland.active.workspace.id;
|
const activeId = Hyprland.active.workspace.id;
|
||||||
|
|
||||||
rev.revealChild = Hyprland.workspaces.some(ws => ws.id > minId &&
|
rev.revealChild = Hyprland.workspaces.some(ws => ws.id > minId &&
|
||||||
|
(ws.windows > 0 ||
|
||||||
|
ws.id === activeId));
|
||||||
|
}]],
|
||||||
|
child: CenterBox({
|
||||||
|
children: [null, EventBox({
|
||||||
|
properties: [['box']],
|
||||||
|
setup: eventbox => eventbox._box = eventbox.child.children[0],
|
||||||
|
connections: [[Hyprland, eventbox => {
|
||||||
|
const maxId = i * VARS.WORKSPACE_PER_ROW + VARS.WORKSPACE_PER_ROW;
|
||||||
|
const activeId = Hyprland.active.workspace.id;
|
||||||
|
|
||||||
|
eventbox._box.revealChild = className === 'special' ||
|
||||||
|
!Hyprland.workspaces.some(ws => ws.id > maxId &&
|
||||||
(ws.windows > 0 ||
|
(ws.windows > 0 ||
|
||||||
ws.id === activeId));
|
ws.id === activeId));
|
||||||
}]],
|
}]],
|
||||||
child: CenterBox({
|
child: Box({
|
||||||
children: [null, EventBox({
|
className: className,
|
||||||
properties: [['box']],
|
children: [
|
||||||
setup: eventbox => eventbox._box = eventbox.child.children[0],
|
Workspace(className === 'special' ? -1 : 1000,
|
||||||
connections: [[Hyprland, eventbox => {
|
className === 'special' ? 'special' : '',
|
||||||
let maxId = i * VARS.WORKSPACE_PER_ROW + VARS.WORKSPACE_PER_ROW;
|
true),
|
||||||
let activeId = Hyprland.active.workspace.id;
|
],
|
||||||
|
}),
|
||||||
eventbox._box.revealChild = className === 'special' ||
|
}), null],
|
||||||
!Hyprland.workspaces.some(ws => ws.id > maxId &&
|
}),
|
||||||
(ws.windows > 0 ||
|
|
||||||
ws.id === activeId));
|
|
||||||
}]],
|
|
||||||
child: Box({
|
|
||||||
className: className,
|
|
||||||
children: [
|
|
||||||
Workspace(className === 'special' ? -1 : 1000,
|
|
||||||
className === 'special' ? 'special' : '',
|
|
||||||
true),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
}), null],
|
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: please make this readable for the love of god
|
// TODO: please make this readable for the love of god
|
||||||
const Workspace = (id, name, extra = false) => {
|
const Workspace = (id, name, extra = false) => {
|
||||||
let workspace;
|
let workspace;
|
||||||
let fixed = Gtk.Fixed.new();
|
const fixed = Gtk.Fixed.new();
|
||||||
|
|
||||||
if (!extra) {
|
if (!extra) {
|
||||||
workspace = Revealer({
|
workspace = Revealer({
|
||||||
transition: 'slide_right',
|
transition: 'slide_right',
|
||||||
transitionDuration: 500,
|
transitionDuration: 500,
|
||||||
properties: [
|
properties: [
|
||||||
['id', id],
|
['id', id],
|
||||||
['name', name],
|
['name', name],
|
||||||
['timeouts', []],
|
['timeouts', []],
|
||||||
['wasActive', false],
|
['wasActive', false],
|
||||||
],
|
],
|
||||||
connections: [[Hyprland, box => {
|
connections: [[Hyprland, box => {
|
||||||
box._timeouts.forEach(timer => timer.destroy());
|
box._timeouts.forEach(timer => GLib.source_remove(timer));
|
||||||
|
|
||||||
let activeId = Hyprland.active.workspace.id;
|
const activeId = Hyprland.active.workspace.id;
|
||||||
let active = activeId === box._id;
|
const active = activeId === box._id;
|
||||||
|
|
||||||
let rev = box.child.child.get_children()[1];
|
const rev = box.child.child.get_children()[1];
|
||||||
let n = activeId > box._id;
|
const n = activeId > box._id;
|
||||||
|
|
||||||
if (Hyprland.getWorkspace(box._id)?.windows > 0 || active) {
|
if (Hyprland.getWorkspace(box._id)?.windows > 0 || active) {
|
||||||
rev.setStyle(DEFAULT_STYLE);
|
rev.setStyle(DEFAULT_STYLE);
|
||||||
box._timeouts.push(setTimeout(() => {
|
box._timeouts.push(Utils.timeout(100, () => {
|
||||||
box.revealChild = true;
|
box.revealChild = true;
|
||||||
}, 100));
|
}));
|
||||||
|
}
|
||||||
|
else if (!Hyprland.getWorkspace(box._id)?.windows > 0) {
|
||||||
|
rev.setStyle(DEFAULT_STYLE);
|
||||||
|
box._timeouts.push(Utils.timeout(100, () => {
|
||||||
|
box.revealChild = false;
|
||||||
|
}));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
if (active) {
|
||||||
else if (!Hyprland.getWorkspace(box._id)?.windows > 0) {
|
rev.setStyle(`${DEFAULT_STYLE}
|
||||||
rev.setStyle(DEFAULT_STYLE);
|
transition: margin 0.5s ease-in-out;
|
||||||
box._timeouts.push(setTimeout(() => {
|
opacity: 1;`);
|
||||||
box.revealChild = false;
|
box._wasActive = true;
|
||||||
}, 100));
|
}
|
||||||
return;
|
else if (box._wasActive) {
|
||||||
}
|
box._timeouts.push(Utils.timeout(120, () => {
|
||||||
|
rev.setStyle(`${DEFAULT_STYLE}
|
||||||
if (active) {
|
transition: margin 0.5s ease-in-out;
|
||||||
rev.setStyle(`${DEFAULT_STYLE}
|
opacity: 1; margin-left: ${n ? '' : '-'}300px;
|
||||||
transition: margin 0.5s ease-in-out;
|
margin-right: ${n ? '-' : ''}300px;`);
|
||||||
opacity: 1;`);
|
box._wasActive = false;
|
||||||
box._wasActive = true;
|
}));
|
||||||
}
|
box._timeouts.push(Utils.timeout(500, () => {
|
||||||
else if (box._wasActive) {
|
rev.setStyle(`${DEFAULT_STYLE} opacity: 0;
|
||||||
box._timeouts.push(setTimeout(() => {
|
margin-left: ${n ? '' : '-'}300px;
|
||||||
rev.setStyle(`${DEFAULT_STYLE}
|
margin-right: ${n ? '-' : ''}300px;`);
|
||||||
transition: margin 0.5s ease-in-out;
|
}));
|
||||||
opacity: 1; margin-left: ${n ? '' : '-'}300px;
|
}
|
||||||
margin-right: ${n ? '-' : ''}300px;`);
|
else {
|
||||||
box._wasActive = false;
|
rev.setStyle(`${DEFAULT_STYLE} opacity: 0;
|
||||||
}, 120));
|
margin-left: ${n ? '' : '-'}300px;
|
||||||
box._timeouts.push(setTimeout(() => {
|
margin-right: ${n ? '-' : ''}300px;`);
|
||||||
rev.setStyle(`${DEFAULT_STYLE} opacity: 0;
|
}
|
||||||
margin-left: ${n ? '' : '-'}300px;
|
}]],
|
||||||
margin-right: ${n ? '-' : ''}300px;`);
|
child: WorkspaceDrop({
|
||||||
}, 500));
|
child: Overlay({
|
||||||
}
|
child: Box({
|
||||||
else {
|
className: 'workspace active',
|
||||||
rev.setStyle(`${DEFAULT_STYLE} opacity: 0;
|
style: `${DEFAULT_STYLE} opacity: 0;`,
|
||||||
margin-left: ${n ? '' : '-'}300px;
|
}),
|
||||||
margin-right: ${n ? '-' : ''}300px;`);
|
overlays: [
|
||||||
}
|
Box({
|
||||||
}]],
|
className: 'workspace active',
|
||||||
child: WorkspaceDrop({
|
style: `${DEFAULT_STYLE} opacity: 0;`,
|
||||||
child: Overlay({
|
}),
|
||||||
child: Box({
|
Box({
|
||||||
className: 'workspace active',
|
className: 'workspace',
|
||||||
style: `${DEFAULT_STYLE} opacity: 0;`,
|
style: DEFAULT_STYLE,
|
||||||
}),
|
child: fixed,
|
||||||
overlays: [
|
}),
|
||||||
Box({
|
],
|
||||||
className: 'workspace active',
|
|
||||||
style: `${DEFAULT_STYLE} opacity: 0;`,
|
|
||||||
}),
|
|
||||||
Box({
|
|
||||||
className: 'workspace',
|
|
||||||
style: DEFAULT_STYLE,
|
|
||||||
child: fixed,
|
|
||||||
})
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
workspace = Revealer({
|
|
||||||
transition: 'slide_right',
|
|
||||||
properties: [
|
|
||||||
['id', id],
|
|
||||||
['name', name],
|
|
||||||
],
|
|
||||||
child: WorkspaceDrop({
|
|
||||||
child: Overlay({
|
|
||||||
child: Box({
|
|
||||||
className: 'workspace',
|
|
||||||
style: DEFAULT_STYLE,
|
|
||||||
}),
|
|
||||||
overlays: [
|
|
||||||
Box({
|
|
||||||
className: 'workspace active',
|
|
||||||
style: `${DEFAULT_STYLE} opacity: 0;`,
|
|
||||||
}),
|
|
||||||
Box({
|
|
||||||
style: DEFAULT_STYLE,
|
|
||||||
children: [
|
|
||||||
fixed,
|
|
||||||
Label({
|
|
||||||
label: ' +',
|
|
||||||
style: 'font-size: 40px;',
|
|
||||||
}),
|
}),
|
||||||
],
|
}),
|
||||||
})
|
});
|
||||||
],
|
}
|
||||||
}),
|
else {
|
||||||
}),
|
workspace = Revealer({
|
||||||
});
|
transition: 'slide_right',
|
||||||
}
|
properties: [
|
||||||
|
['id', id],
|
||||||
|
['name', name],
|
||||||
|
],
|
||||||
|
child: WorkspaceDrop({
|
||||||
|
child: Overlay({
|
||||||
|
child: Box({
|
||||||
|
className: 'workspace',
|
||||||
|
style: DEFAULT_STYLE,
|
||||||
|
}),
|
||||||
|
overlays: [
|
||||||
|
Box({
|
||||||
|
className: 'workspace active',
|
||||||
|
style: `${DEFAULT_STYLE} opacity: 0;`,
|
||||||
|
}),
|
||||||
|
Box({
|
||||||
|
style: DEFAULT_STYLE,
|
||||||
|
children: [
|
||||||
|
fixed,
|
||||||
|
Label({
|
||||||
|
label: ' +',
|
||||||
|
style: 'font-size: 40px;',
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
workspace.getFixed = () => fixed;
|
workspace.getFixed = () => fixed;
|
||||||
return workspace;
|
return workspace;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function updateWorkspaces(box) {
|
export function updateWorkspaces(box) {
|
||||||
Hyprland.workspaces.forEach(ws => {
|
Hyprland.workspaces.forEach(ws => {
|
||||||
let currentWs = box._workspaces.find(ch => ch._id == ws.id);
|
const currentWs = box._workspaces.find(ch => ch._id == ws.id);
|
||||||
if (!currentWs) {
|
if (!currentWs) {
|
||||||
var type = 0;
|
var type = 0;
|
||||||
var rowNo = 0;
|
var rowNo = 0;
|
||||||
|
|
||||||
if (ws.id < 0) {
|
if (ws.id < 0) {
|
||||||
// This means it's a special workspace
|
// This means it's a special workspace
|
||||||
type = 1;
|
type = 1;
|
||||||
}
|
}
|
||||||
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) {
|
if (rowNo >= box.children[type].children.length) {
|
||||||
for (let i = box.children[type].children.length; i <= rowNo; ++i) {
|
for (let i = box.children[type].children.length; i <= rowNo; ++i)
|
||||||
box.children[type].add(WorkspaceRow(type ? 'special' : 'normal', i));
|
box.children[type].add(WorkspaceRow(type ? 'special' : 'normal', i));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
var row = box.children[type].children[rowNo].child.centerWidget.child;
|
||||||
|
row.add(Workspace(ws.id, type ? ws.name : ''));
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
var row = box.children[type].children[rowNo].child.centerWidget.child;
|
box.show_all();
|
||||||
row.add(Workspace(ws.id, type ? ws.name : ''));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
box.show_all();
|
|
||||||
|
|
||||||
// Make sure the order is correct
|
// Make sure the order is correct
|
||||||
box._workspaces.forEach((workspace, i) => {
|
box._workspaces.forEach((workspace, i) => {
|
||||||
workspace.get_parent().reorder_child(workspace, i)
|
workspace.get_parent().reorder_child(workspace, i);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,46 +2,46 @@ import { Widget } from '../imports.js';
|
||||||
const { CenterBox, Label } = Widget;
|
const { CenterBox, Label } = Widget;
|
||||||
|
|
||||||
import PopupWindow from './misc/popup.js';
|
import PopupWindow from './misc/popup.js';
|
||||||
import Button from './misc/cursorbox.js'
|
import Button from './misc/cursorbox.js';
|
||||||
|
|
||||||
|
|
||||||
const PowermenuWidget = () => CenterBox({
|
const PowermenuWidget = () => CenterBox({
|
||||||
className: 'powermenu',
|
className: 'powermenu',
|
||||||
vertical: false,
|
vertical: false,
|
||||||
|
|
||||||
startWidget: Button({
|
startWidget: Button({
|
||||||
type: "Button",
|
type: 'Button',
|
||||||
className: 'shutdown',
|
className: 'shutdown',
|
||||||
onPrimaryClickRelease: 'systemctl poweroff',
|
onPrimaryClickRelease: 'systemctl poweroff',
|
||||||
|
|
||||||
child: Label({
|
child: Label({
|
||||||
label: '襤',
|
label: '襤',
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
}),
|
|
||||||
|
|
||||||
centerWidget: Button({
|
centerWidget: Button({
|
||||||
type: "Button",
|
type: 'Button',
|
||||||
className: 'reboot',
|
className: 'reboot',
|
||||||
onPrimaryClickRelease: 'systemctl reboot',
|
onPrimaryClickRelease: 'systemctl reboot',
|
||||||
|
|
||||||
child: Label({
|
child: Label({
|
||||||
label: '勒',
|
label: '勒',
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
}),
|
|
||||||
|
|
||||||
endWidget: Button({
|
endWidget: Button({
|
||||||
type: "Button",
|
type: 'Button',
|
||||||
className: 'logout',
|
className: 'logout',
|
||||||
onPrimaryClickRelease: 'hyprctl dispatch exit',
|
onPrimaryClickRelease: 'hyprctl dispatch exit',
|
||||||
|
|
||||||
child: Label({
|
child: Label({
|
||||||
label: '',
|
label: '',
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default () => PopupWindow({
|
export default () => PopupWindow({
|
||||||
name: 'powermenu',
|
name: 'powermenu',
|
||||||
transition: 'crossfade',
|
transition: 'crossfade',
|
||||||
child: PowermenuWidget(),
|
child: PowermenuWidget(),
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,240 +6,237 @@ import EventBox from '../misc/cursorbox.js';
|
||||||
|
|
||||||
|
|
||||||
const GridButton = ({
|
const GridButton = ({
|
||||||
command = () => {},
|
command = () => {},
|
||||||
secondaryCommand = () => {},
|
secondaryCommand = () => {},
|
||||||
icon
|
icon,
|
||||||
} = {}) => Box({
|
} = {}) => Box({
|
||||||
className: 'grid-button',
|
className: 'grid-button',
|
||||||
children: [
|
children: [
|
||||||
|
|
||||||
EventBox({
|
EventBox({
|
||||||
className: 'left-part',
|
className: 'left-part',
|
||||||
onPrimaryClickRelease: () => command(),
|
onPrimaryClickRelease: () => command(),
|
||||||
child: icon,
|
child: icon,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
EventBox({
|
EventBox({
|
||||||
className: 'right-part',
|
className: 'right-part',
|
||||||
onPrimaryClickRelease: () => secondaryCommand(),
|
onPrimaryClickRelease: () => secondaryCommand(),
|
||||||
child: Label({
|
child: Label({
|
||||||
label: " ",
|
label: ' ',
|
||||||
className: 'grid-chev',
|
className: 'grid-chev',
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
const FirstRow = () => Box({
|
const FirstRow = () => Box({
|
||||||
className: 'button-row',
|
className: 'button-row',
|
||||||
halign: 'center',
|
halign: 'center',
|
||||||
style: 'margin-top: 15px; margin-bottom: 7px;',
|
style: 'margin-top: 15px; margin-bottom: 7px;',
|
||||||
children: [
|
children: [
|
||||||
|
|
||||||
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: Icon({
|
icon: Icon({
|
||||||
className: 'grid-label',
|
className: 'grid-label',
|
||||||
connections: [[Network, icon => {
|
connections: [[Network, icon => {
|
||||||
if (Network.wifi.enabled) {
|
if (Network.wifi.enabled)
|
||||||
icon.icon = 'network-wireless-connected-symbolic';
|
icon.icon = 'network-wireless-connected-symbolic';
|
||||||
}
|
|
||||||
else {
|
|
||||||
icon.icon = 'network-wireless-offline-symbolic';
|
|
||||||
}
|
|
||||||
}, 'changed']],
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
|
|
||||||
GridButton({
|
else
|
||||||
command: () => {
|
icon.icon = 'network-wireless-offline-symbolic';
|
||||||
execAsync(['bash', '-c', '$AGS_PATH/qs-toggles.sh blue-toggle'])
|
}, 'changed']],
|
||||||
.catch(print);
|
}),
|
||||||
},
|
}),
|
||||||
secondaryCommand: () => {
|
|
||||||
execAsync(['bash', '-c', 'blueberry'])
|
|
||||||
.catch(print)
|
|
||||||
},
|
|
||||||
icon: Icon({
|
|
||||||
className: 'grid-label',
|
|
||||||
connections: [[Bluetooth, self => {
|
|
||||||
if (Bluetooth.enabled) {
|
|
||||||
self.icon = 'bluetooth-active-symbolic';
|
|
||||||
execAsync(['bash', '-c', 'echo > $HOME/.config/.bluetooth'])
|
|
||||||
.catch(print);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
self.icon = 'bluetooth-disabled-symbolic';
|
|
||||||
execAsync(['bash', '-c', 'echo > $HOME/.config/.bluetooth'])
|
|
||||||
.catch(print);
|
|
||||||
}
|
|
||||||
}, 'changed']],
|
|
||||||
})
|
|
||||||
}),
|
|
||||||
|
|
||||||
GridButton({
|
GridButton({
|
||||||
command: () => {
|
command: () => {
|
||||||
execAsync(['bash', '-c', '$AGS_PATH/qs-toggles.sh toggle-radio'])
|
execAsync(['bash', '-c', '$AGS_PATH/qs-toggles.sh blue-toggle'])
|
||||||
.catch(print);
|
.catch(print);
|
||||||
},
|
},
|
||||||
secondaryCommand: () => {
|
secondaryCommand: () => {
|
||||||
execAsync(['notify-send', 'set this up moron'])
|
execAsync(['bash', '-c', 'blueberry'])
|
||||||
.catch(print);
|
.catch(print);
|
||||||
},
|
},
|
||||||
icon: Icon({
|
icon: Icon({
|
||||||
className: 'grid-label',
|
className: 'grid-label',
|
||||||
connections: [[Network, self => {
|
connections: [[Bluetooth, self => {
|
||||||
if (Network.wifi.enabled)
|
if (Bluetooth.enabled) {
|
||||||
self.icon = 'airplane-mode-disabled-symbolic';
|
self.icon = 'bluetooth-active-symbolic';
|
||||||
else
|
execAsync(['bash', '-c', 'echo > $HOME/.config/.bluetooth'])
|
||||||
self.icon = 'airplane-mode-symbolic';
|
.catch(print);
|
||||||
}, 'changed']],
|
}
|
||||||
}),
|
else {
|
||||||
}),
|
self.icon = 'bluetooth-disabled-symbolic';
|
||||||
|
execAsync(['bash', '-c', 'echo > $HOME/.config/.bluetooth'])
|
||||||
|
.catch(print);
|
||||||
|
}
|
||||||
|
}, 'changed']],
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
|
||||||
],
|
GridButton({
|
||||||
|
command: () => {
|
||||||
|
execAsync(['bash', '-c', '$AGS_PATH/qs-toggles.sh toggle-radio'])
|
||||||
|
.catch(print);
|
||||||
|
},
|
||||||
|
secondaryCommand: () => {
|
||||||
|
execAsync(['notify-send', 'set this up moron'])
|
||||||
|
.catch(print);
|
||||||
|
},
|
||||||
|
icon: Icon({
|
||||||
|
className: 'grid-label',
|
||||||
|
connections: [[Network, self => {
|
||||||
|
if (Network.wifi.enabled)
|
||||||
|
self.icon = 'airplane-mode-disabled-symbolic';
|
||||||
|
else
|
||||||
|
self.icon = 'airplane-mode-symbolic';
|
||||||
|
}, 'changed']],
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
const SubRow = () => CenterBox({
|
const SubRow = () => CenterBox({
|
||||||
halign: 'start',
|
halign: 'start',
|
||||||
children: [
|
children: [
|
||||||
|
|
||||||
Label({
|
Label({
|
||||||
className: 'sub-label',
|
className: 'sub-label',
|
||||||
truncate: 'end',
|
truncate: 'end',
|
||||||
maxWidthChars: 12,
|
maxWidthChars: 12,
|
||||||
connections: [[Network, self => {
|
connections: [[Network, self => {
|
||||||
// TODO: handle ethernet too
|
// TODO: handle ethernet too
|
||||||
self.label = Network.wifi.ssid;
|
self.label = Network.wifi.ssid;
|
||||||
}, 'changed']],
|
}, 'changed']],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
Label({
|
Label({
|
||||||
className: 'sub-label',
|
className: 'sub-label',
|
||||||
truncate: 'end',
|
truncate: 'end',
|
||||||
maxWidthChars: 12,
|
maxWidthChars: 12,
|
||||||
connections: [[Bluetooth, self => {
|
connections: [[Bluetooth, self => {
|
||||||
if (Bluetooth.connectedDevices[0])
|
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']],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
null,
|
null,
|
||||||
|
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
const items = {
|
const items = {
|
||||||
101: 'audio-volume-overamplified-symbolic',
|
101: 'audio-volume-overamplified-symbolic',
|
||||||
67: 'audio-volume-high-symbolic',
|
67: 'audio-volume-high-symbolic',
|
||||||
34: 'audio-volume-medium-symbolic',
|
34: 'audio-volume-medium-symbolic',
|
||||||
1: 'audio-volume-low-symbolic',
|
1: 'audio-volume-low-symbolic',
|
||||||
0: 'audio-volume-muted-symbolic',
|
0: 'audio-volume-muted-symbolic',
|
||||||
};
|
};
|
||||||
|
|
||||||
const itemsMic = {
|
const itemsMic = {
|
||||||
2: 'audio-input-microphone-high-symbolic',
|
2: 'audio-input-microphone-high-symbolic',
|
||||||
1: 'audio-input-microphone-muted-symbolic',
|
1: 'audio-input-microphone-muted-symbolic',
|
||||||
0: 'audio-input-microphone-muted-symbolic',
|
0: 'audio-input-microphone-muted-symbolic',
|
||||||
};
|
};
|
||||||
|
|
||||||
const SecondRow = () => Box({
|
const SecondRow = () => Box({
|
||||||
className: 'button-row',
|
className: 'button-row',
|
||||||
halign: 'center',
|
halign: 'center',
|
||||||
style: 'margin-top: 7px; margin-bottom: 15px;',
|
style: 'margin-top: 7px; margin-bottom: 15px;',
|
||||||
children: [
|
children: [
|
||||||
|
|
||||||
GridButton({
|
GridButton({
|
||||||
command: () => {
|
command: () => {
|
||||||
execAsync(['swayosd-client', '--output-volume', 'mute-toggle'])
|
execAsync(['swayosd-client', '--output-volume', 'mute-toggle'])
|
||||||
.catch(print);
|
.catch(print);
|
||||||
},
|
},
|
||||||
|
|
||||||
secondaryCommand: () => {
|
secondaryCommand: () => {
|
||||||
execAsync(['bash', '-c', 'pavucontrol'])
|
execAsync(['bash', '-c', 'pavucontrol'])
|
||||||
.catch(print);
|
.catch(print);
|
||||||
},
|
},
|
||||||
|
|
||||||
icon: Icon({
|
icon: Icon({
|
||||||
className: 'grid-label',
|
className: 'grid-label',
|
||||||
connections: [[Audio, icon => {
|
connections: [[Audio, icon => {
|
||||||
if (Audio.speaker) {
|
if (Audio.speaker) {
|
||||||
if (Audio.speaker.stream.isMuted) {
|
if (Audio.speaker.stream.isMuted) {
|
||||||
icon.icon = items[0];
|
icon.icon = items[0];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
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)
|
||||||
icon.icon = items[threshold + 1];
|
icon.icon = items[threshold + 1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}, 'speaker-changed']],
|
||||||
}, 'speaker-changed']],
|
}),
|
||||||
}),
|
}),
|
||||||
}),
|
|
||||||
|
|
||||||
GridButton({
|
GridButton({
|
||||||
command: () => {
|
command: () => {
|
||||||
execAsync(['swayosd-client', '--input-volume', 'mute-toggle'])
|
execAsync(['swayosd-client', '--input-volume', 'mute-toggle'])
|
||||||
.catch(print);
|
.catch(print);
|
||||||
},
|
},
|
||||||
|
|
||||||
secondaryCommand: () => {
|
secondaryCommand: () => {
|
||||||
execAsync(['bash', '-c', 'pavucontrol'])
|
execAsync(['bash', '-c', 'pavucontrol'])
|
||||||
.catch(print);
|
.catch(print);
|
||||||
},
|
},
|
||||||
|
|
||||||
icon: Icon({
|
icon: Icon({
|
||||||
className: 'grid-label',
|
className: 'grid-label',
|
||||||
connections: [[Audio, icon => {
|
connections: [[Audio, icon => {
|
||||||
if (Audio.microphone) {
|
if (Audio.microphone) {
|
||||||
if (Audio.microphone.stream.isMuted) {
|
if (Audio.microphone.stream.isMuted) {
|
||||||
icon.icon = itemsMic[0];
|
icon.icon = itemsMic[0];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const vol = Audio.microphone.volume * 100;
|
const vol = Audio.microphone.volume * 100;
|
||||||
for (const threshold of [-1, 0, 1]) {
|
for (const threshold of [-1, 0, 1]) {
|
||||||
if (vol > threshold + 1) {
|
if (vol > threshold + 1)
|
||||||
icon.icon = itemsMic[threshold + 1];
|
icon.icon = itemsMic[threshold + 1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}, 'microphone-changed']],
|
||||||
}, 'microphone-changed']],
|
}),
|
||||||
})
|
}),
|
||||||
}),
|
|
||||||
|
|
||||||
GridButton({
|
GridButton({
|
||||||
command: () => {
|
command: () => {
|
||||||
execAsync(['bash', '-c', '$LOCK_PATH/lock.sh'])
|
execAsync(['bash', '-c', '$LOCK_PATH/lock.sh'])
|
||||||
.catch(print);
|
.catch(print);
|
||||||
},
|
},
|
||||||
secondaryCommand: () => App.openWindow('powermenu'),
|
secondaryCommand: () => App.openWindow('powermenu'),
|
||||||
icon: Label({
|
icon: Label({
|
||||||
className: 'grid-label',
|
className: 'grid-label',
|
||||||
label: " ",
|
label: ' ',
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
export default () => Box({
|
export default () => Box({
|
||||||
className: 'button-grid',
|
className: 'button-grid',
|
||||||
vertical: true,
|
vertical: true,
|
||||||
halign: 'center',
|
halign: 'center',
|
||||||
children: [
|
children: [
|
||||||
FirstRow(),
|
FirstRow(),
|
||||||
SubRow(),
|
SubRow(),
|
||||||
SecondRow(),
|
SecondRow(),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
|
@ -9,42 +9,42 @@ import ToggleButton from './toggle-button.js';
|
||||||
|
|
||||||
|
|
||||||
const QuickSettingsWidget = () => Box({
|
const QuickSettingsWidget = () => Box({
|
||||||
className: 'qs-container',
|
className: 'qs-container',
|
||||||
vertical: true,
|
vertical: true,
|
||||||
children: [
|
children: [
|
||||||
|
|
||||||
Box({
|
Box({
|
||||||
className: 'quick-settings',
|
className: 'quick-settings',
|
||||||
vertical: true,
|
vertical: true,
|
||||||
children: [
|
children: [
|
||||||
|
|
||||||
Label({
|
Label({
|
||||||
label: 'Control Center',
|
label: 'Control Center',
|
||||||
className: 'title',
|
className: 'title',
|
||||||
halign: 'start',
|
halign: 'start',
|
||||||
style: 'margin-left: 20px'
|
style: 'margin-left: 20px',
|
||||||
|
}),
|
||||||
|
|
||||||
|
ButtonGrid(),
|
||||||
|
|
||||||
|
SliderBox(),
|
||||||
|
|
||||||
|
ToggleButton(),
|
||||||
|
|
||||||
|
],
|
||||||
}),
|
}),
|
||||||
|
|
||||||
ButtonGrid(),
|
Revealer({
|
||||||
|
transition: 'slide_down',
|
||||||
|
child: Player(),
|
||||||
|
}),
|
||||||
|
|
||||||
SliderBox(),
|
],
|
||||||
|
|
||||||
ToggleButton(),
|
|
||||||
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
|
|
||||||
Revealer({
|
|
||||||
transition: 'slide_down',
|
|
||||||
child: Player(),
|
|
||||||
})
|
|
||||||
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default () => PopupWindow({
|
export default () => PopupWindow({
|
||||||
name: 'quick-settings',
|
name: 'quick-settings',
|
||||||
anchor: [ 'top', 'right' ],
|
anchor: ['top', 'right'],
|
||||||
margin: [ 8, 5, 0, ],
|
margin: [8, 5, 0],
|
||||||
child: QuickSettingsWidget(),
|
child: QuickSettingsWidget(),
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,93 +3,91 @@ const { Box, Slider, Icon, EventBox } = Widget;
|
||||||
const { execAsync } = Utils;
|
const { execAsync } = Utils;
|
||||||
|
|
||||||
const items = {
|
const items = {
|
||||||
101: 'audio-volume-overamplified-symbolic',
|
101: 'audio-volume-overamplified-symbolic',
|
||||||
67: 'audio-volume-high-symbolic',
|
67: 'audio-volume-high-symbolic',
|
||||||
34: 'audio-volume-medium-symbolic',
|
34: 'audio-volume-medium-symbolic',
|
||||||
1: 'audio-volume-low-symbolic',
|
1: 'audio-volume-low-symbolic',
|
||||||
0: 'audio-volume-muted-symbolic',
|
0: 'audio-volume-muted-symbolic',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export default () => Box({
|
export default () => Box({
|
||||||
className: 'slider-box',
|
className: 'slider-box',
|
||||||
vertical: true,
|
vertical: true,
|
||||||
halign: 'center',
|
halign: 'center',
|
||||||
children: [
|
children: [
|
||||||
|
|
||||||
Box({
|
Box({
|
||||||
className: 'slider',
|
className: 'slider',
|
||||||
valign: 'start',
|
valign: 'start',
|
||||||
halign: 'center',
|
halign: 'center',
|
||||||
children: [
|
children: [
|
||||||
Icon({
|
Icon({
|
||||||
size: 26,
|
size: 26,
|
||||||
className: 'slider-label',
|
className: 'slider-label',
|
||||||
connections: [[Audio, icon => {
|
connections: [[Audio, icon => {
|
||||||
if (Audio.speaker) {
|
if (Audio.speaker) {
|
||||||
if (Audio.speaker.stream.isMuted) {
|
if (Audio.speaker.stream.isMuted) {
|
||||||
icon.icon = items[0];
|
icon.icon = items[0];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
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)
|
||||||
icon.icon = items[threshold + 1];
|
icon.icon = items[threshold + 1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}, 'speaker-changed']],
|
||||||
}, 'speaker-changed']],
|
}),
|
||||||
}),
|
|
||||||
|
|
||||||
Slider({
|
Slider({
|
||||||
connections: [[Audio, slider => {
|
connections: [[Audio, slider => {
|
||||||
if (Audio.speaker) {
|
if (Audio.speaker)
|
||||||
slider.value = Audio.speaker.volume;
|
slider.value = Audio.speaker.volume;
|
||||||
}
|
}, 'speaker-changed']],
|
||||||
}, 'speaker-changed']],
|
onChange: ({ value }) => Audio.speaker.volume = value,
|
||||||
onChange: ({ value }) => Audio.speaker.volume = value,
|
max: 0.999,
|
||||||
max: 0.999,
|
draw_value: false,
|
||||||
draw_value: false,
|
}),
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
|
|
||||||
Box({
|
|
||||||
className: 'slider',
|
|
||||||
valign: 'start',
|
|
||||||
halign: 'center',
|
|
||||||
children: [
|
|
||||||
Icon({
|
|
||||||
className: 'slider-label',
|
|
||||||
icon: 'display-brightness-symbolic',
|
|
||||||
}),
|
|
||||||
|
|
||||||
EventBox({
|
|
||||||
onHover: box => box.child._canChange = false,
|
|
||||||
onHoverLost: box => box.child._canChange = true,
|
|
||||||
child: Slider({
|
|
||||||
properties: [
|
|
||||||
['canChange', true],
|
|
||||||
],
|
],
|
||||||
onChange: ({ value }) => {
|
|
||||||
execAsync(`brightnessctl set ${value}`)
|
|
||||||
.catch(print);
|
|
||||||
},
|
|
||||||
connections: [[1000, slider => {
|
|
||||||
if (slider._canChange) {
|
|
||||||
execAsync('brightnessctl get')
|
|
||||||
.then(out => slider.value = out)
|
|
||||||
.catch(print);
|
|
||||||
}
|
|
||||||
}]],
|
|
||||||
min: 0,
|
|
||||||
max: 255,
|
|
||||||
draw_value: false,
|
|
||||||
}),
|
|
||||||
}),
|
}),
|
||||||
],
|
|
||||||
}),
|
|
||||||
|
|
||||||
],
|
Box({
|
||||||
|
className: 'slider',
|
||||||
|
valign: 'start',
|
||||||
|
halign: 'center',
|
||||||
|
children: [
|
||||||
|
Icon({
|
||||||
|
className: 'slider-label',
|
||||||
|
icon: 'display-brightness-symbolic',
|
||||||
|
}),
|
||||||
|
|
||||||
|
EventBox({
|
||||||
|
onHover: box => box.child._canChange = false,
|
||||||
|
onHoverLost: box => box.child._canChange = true,
|
||||||
|
child: Slider({
|
||||||
|
properties: [
|
||||||
|
['canChange', true],
|
||||||
|
],
|
||||||
|
onChange: ({ value }) => {
|
||||||
|
execAsync(`brightnessctl set ${value}`)
|
||||||
|
.catch(print);
|
||||||
|
},
|
||||||
|
connections: [[1000, slider => {
|
||||||
|
if (slider._canChange) {
|
||||||
|
execAsync('brightnessctl get')
|
||||||
|
.then(out => slider.value = out)
|
||||||
|
.catch(print);
|
||||||
|
}
|
||||||
|
}]],
|
||||||
|
min: 0,
|
||||||
|
max: 255,
|
||||||
|
draw_value: false,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,38 +5,38 @@ import Gtk from 'gi://Gtk';
|
||||||
import EventBox from '../misc/cursorbox.js';
|
import EventBox from '../misc/cursorbox.js';
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
let widget = EventBox({});
|
const widget = EventBox({});
|
||||||
|
|
||||||
let toggleButton = Gtk.ToggleButton.new();
|
const toggleButton = Gtk.ToggleButton.new();
|
||||||
toggleButton.add(Icon({
|
toggleButton.add(Icon({
|
||||||
icon: 'go-down-symbolic',
|
icon: 'go-down-symbolic',
|
||||||
className: 'arrow',
|
className: 'arrow',
|
||||||
style: `-gtk-icon-transform: rotate(180deg);`,
|
style: '-gtk-icon-transform: rotate(180deg);',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Setup
|
// Setup
|
||||||
const id = Mpris.connect('changed', () => {
|
const id = Mpris.connect('changed', () => {
|
||||||
toggleButton.set_active(Mpris.players.length > 0);
|
toggleButton.set_active(Mpris.players.length > 0);
|
||||||
Mpris.disconnect(id);
|
Mpris.disconnect(id);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Connections
|
// Connections
|
||||||
toggleButton.connect('toggled', () => {
|
toggleButton.connect('toggled', () => {
|
||||||
let rev = toggleButton.get_parent().get_parent().get_parent().children[1];
|
const rev = toggleButton.get_parent().get_parent().get_parent().children[1];
|
||||||
|
|
||||||
if (toggleButton.get_active()) {
|
if (toggleButton.get_active()) {
|
||||||
toggleButton.get_children()[0]
|
toggleButton.get_children()[0]
|
||||||
.setStyle("-gtk-icon-transform: rotate(0deg);");
|
.setStyle('-gtk-icon-transform: rotate(0deg);');
|
||||||
rev.revealChild = true;
|
rev.revealChild = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
toggleButton.get_children()[0]
|
toggleButton.get_children()[0]
|
||||||
.setStyle('-gtk-icon-transform: rotate(180deg);');
|
.setStyle('-gtk-icon-transform: rotate(180deg);');
|
||||||
rev.revealChild = false;
|
rev.revealChild = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
widget.add(toggleButton);
|
widget.add(toggleButton);
|
||||||
|
|
||||||
return widget;
|
return widget;
|
||||||
}
|
};
|
||||||
|
|
|
@ -9,22 +9,22 @@ export const RoundedCorner = (place, props) => Widget({
|
||||||
valign: place.includes('top') ? 'start' : 'end',
|
valign: place.includes('top') ? 'start' : 'end',
|
||||||
setup: widget => {
|
setup: widget => {
|
||||||
const r = widget.get_style_context()
|
const 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, (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()
|
const 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) {
|
||||||
|
@ -54,9 +54,9 @@ export const RoundedCorner = (place, props) => Widget({
|
||||||
cr.fill();
|
cr.fill();
|
||||||
cr.setLineWidth(borderWidth);
|
cr.setLineWidth(borderWidth);
|
||||||
cr.setSourceRGBA(borderColor.red,
|
cr.setSourceRGBA(borderColor.red,
|
||||||
borderColor.green,
|
borderColor.green,
|
||||||
borderColor.blue,
|
borderColor.blue,
|
||||||
borderColor.alpha);
|
borderColor.alpha);
|
||||||
cr.stroke();
|
cr.stroke();
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
@ -68,7 +68,7 @@ export const Topleft = () => Widget.Window({
|
||||||
anchor: ['top', 'left'],
|
anchor: ['top', 'left'],
|
||||||
exclusive: false,
|
exclusive: false,
|
||||||
visible: true,
|
visible: true,
|
||||||
child: RoundedCorner('topleft', { className: 'corner', }),
|
child: RoundedCorner('topleft', { className: 'corner' }),
|
||||||
});
|
});
|
||||||
export const Topright = () => Widget.Window({
|
export const Topright = () => Widget.Window({
|
||||||
name: 'cornertr',
|
name: 'cornertr',
|
||||||
|
@ -76,7 +76,7 @@ export const Topright = () => Widget.Window({
|
||||||
anchor: ['top', 'right'],
|
anchor: ['top', 'right'],
|
||||||
exclusive: false,
|
exclusive: false,
|
||||||
visible: true,
|
visible: true,
|
||||||
child: RoundedCorner('topright', { className: 'corner', }),
|
child: RoundedCorner('topright', { className: 'corner' }),
|
||||||
});
|
});
|
||||||
export const Bottomleft = () => Widget.Window({
|
export const Bottomleft = () => Widget.Window({
|
||||||
name: 'cornerbl',
|
name: 'cornerbl',
|
||||||
|
@ -84,7 +84,7 @@ export const Bottomleft = () => Widget.Window({
|
||||||
anchor: ['bottom', 'left'],
|
anchor: ['bottom', 'left'],
|
||||||
exclusive: false,
|
exclusive: false,
|
||||||
visible: true,
|
visible: true,
|
||||||
child: RoundedCorner('bottomleft', { className: 'corner', }),
|
child: RoundedCorner('bottomleft', { className: 'corner' }),
|
||||||
});
|
});
|
||||||
export const Bottomright = () => Widget.Window({
|
export const Bottomright = () => Widget.Window({
|
||||||
name: 'cornerbr',
|
name: 'cornerbr',
|
||||||
|
@ -92,5 +92,5 @@ export const Bottomright = () => Widget.Window({
|
||||||
anchor: ['bottom', 'right'],
|
anchor: ['bottom', 'right'],
|
||||||
exclusive: false,
|
exclusive: false,
|
||||||
visible: true,
|
visible: true,
|
||||||
child: RoundedCorner('bottomright', { className: 'corner', }),
|
child: RoundedCorner('bottomright', { className: 'corner' }),
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@girs/gtk-3.0": "^3.24.39-3.2.2",
|
"@girs/gtk-3.0": "^3.24.39-3.2.2",
|
||||||
"eslint": "^8.52.0"
|
"eslint": "^8.52.0",
|
||||||
|
"stylelint-config-standard-scss": "^11.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
.corner {
|
.corner {
|
||||||
background-color: black;
|
background-color: black;
|
||||||
border-radius: 18px; //Hard code because Hyprland rounding is in px
|
border-radius: 18px; //Hard code because Hyprland rounding is in px
|
||||||
border-width: 0.068rem;
|
border-width: 0.068rem;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,26 +21,26 @@
|
||||||
}
|
}
|
||||||
button {
|
button {
|
||||||
all: unset;
|
all: unset;
|
||||||
transition: 200ms;
|
transition: 200ms;
|
||||||
border-radius: 9px;
|
border-radius: 9px;
|
||||||
color: #eee;
|
color: #eee;
|
||||||
background-color: #664C90;
|
background-color: #664C90;
|
||||||
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03);
|
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03);
|
||||||
padding: 4.5px 9px;
|
padding: 4.5px 9px;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03);
|
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03);
|
||||||
background-color: rgba(238, 238, 238, 0.154);
|
background-color: rgba(238, 238, 238, 0.154);
|
||||||
color: #f1f1f1;
|
color: #f1f1f1;
|
||||||
}
|
}
|
||||||
&:disabled {
|
&:disabled {
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
background-color: rgba(#664C90, 0.3);
|
background-color: rgba(#664C90, 0.3);
|
||||||
color: rgba(238, 238, 238, 0.3);
|
color: rgba(238, 238, 238, 0.3);
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,51 +50,51 @@
|
||||||
border-radius: 30px;
|
border-radius: 30px;
|
||||||
border-top: 2px solid $contrastbg;
|
border-top: 2px solid $contrastbg;
|
||||||
box-shadow: 0 0 6px 0 rgba(0, 0, 0, 0.5);
|
box-shadow: 0 0 6px 0 rgba(0, 0, 0, 0.5);
|
||||||
scrollbar {
|
scrollbar {
|
||||||
all: unset;
|
all: unset;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
border-top-left-radius: 0;
|
border-top-left-radius: 0;
|
||||||
border-bottom-left-radius: 0;
|
border-bottom-left-radius: 0;
|
||||||
* {
|
* {
|
||||||
all: unset;
|
all: unset;
|
||||||
}
|
}
|
||||||
&:hover {
|
&:hover {
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
border-top-left-radius: 0;
|
border-top-left-radius: 0;
|
||||||
border-bottom-left-radius: 0;
|
border-bottom-left-radius: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
scrollbar.vertical {
|
scrollbar.vertical {
|
||||||
transition: 200ms;
|
transition: 200ms;
|
||||||
background-color: rgba(23, 23, 23, 0.3);
|
background-color: rgba(23, 23, 23, 0.3);
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: rgba(23, 23, 23, 0.7);
|
background-color: rgba(23, 23, 23, 0.7);
|
||||||
slider {
|
slider {
|
||||||
background-color: rgba(238, 238, 238, 0.7);
|
background-color: rgba(238, 238, 238, 0.7);
|
||||||
min-width: .6em;
|
min-width: .6em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
slider {
|
slider {
|
||||||
background-color: rgba(238, 238, 238, 0.5);
|
background-color: rgba(238, 238, 238, 0.5);
|
||||||
border-radius: 9px;
|
border-radius: 9px;
|
||||||
min-width: .4em;
|
min-width: .4em;
|
||||||
min-height: 2em;
|
min-height: 2em;
|
||||||
transition: 200ms;
|
transition: 200ms;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.placeholder {
|
.placeholder {
|
||||||
color: white;
|
color: white;
|
||||||
image {
|
image {
|
||||||
font-size: 7em;
|
font-size: 7em;
|
||||||
text-shadow: 2px 2px 2px rgba(0, 0, 0, 0.6);
|
text-shadow: 2px 2px 2px rgba(0, 0, 0, 0.6);
|
||||||
-gtk-icon-shadow: 2px 2px 2px rgba(0, 0, 0, 0.6);
|
-gtk-icon-shadow: 2px 2px 2px rgba(0, 0, 0, 0.6);
|
||||||
}
|
}
|
||||||
label {
|
label {
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
text-shadow: 2px 2px 2px rgba(0, 0, 0, 0.6);
|
text-shadow: 2px 2px 2px rgba(0, 0, 0, 0.6);
|
||||||
-gtk-icon-shadow: 2px 2px 2px rgba(0, 0, 0, 0.6);
|
-gtk-icon-shadow: 2px 2px 2px rgba(0, 0, 0, 0.6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,170 +10,170 @@ $background-color_9: rgba(238, 238, 238, 0.7);
|
||||||
$background-color_10: rgba(238, 238, 238, 0.5);
|
$background-color_10: rgba(238, 238, 238, 0.5);
|
||||||
|
|
||||||
.notification.critical {
|
.notification.critical {
|
||||||
>box {
|
>box {
|
||||||
box-shadow: inset 0 0 0.5em 0 #e67090;
|
box-shadow: inset 0 0 0.5em 0 #e67090;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.notification {
|
.notification {
|
||||||
>box {
|
>box {
|
||||||
all: unset;
|
all: unset;
|
||||||
box-shadow: 0 0 4.5px 0 rgba(0, 0, 0, 0.4);
|
box-shadow: 0 0 4.5px 0 rgba(0, 0, 0, 0.4);
|
||||||
margin: 9px 9px 0 9px;
|
margin: 9px 9px 0 9px;
|
||||||
border: 2px solid $contrastbg;
|
border: 2px solid $contrastbg;
|
||||||
border-radius: 15px;
|
border-radius: 15px;
|
||||||
background-color: $bg;
|
background-color: $bg;
|
||||||
padding: 16.2px;
|
padding: 16.2px;
|
||||||
* {
|
* {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&:hover {
|
&:hover {
|
||||||
.close-button {
|
.close-button {
|
||||||
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03);
|
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03);
|
||||||
background-color: $background-color_1;
|
background-color: $background-color_1;
|
||||||
background-color: $background-color_2;
|
background-color: $background-color_2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.title {
|
.title {
|
||||||
margin-right: 9px;
|
margin-right: 9px;
|
||||||
font-size: 1.1em;
|
font-size: 1.1em;
|
||||||
}
|
}
|
||||||
.description {
|
.description {
|
||||||
font-size: .9em;
|
font-size: .9em;
|
||||||
min-width: 350px;
|
min-width: 350px;
|
||||||
}
|
}
|
||||||
.icon {
|
.icon {
|
||||||
border-radius: 7.2px;
|
border-radius: 7.2px;
|
||||||
margin-right: 9px;
|
margin-right: 9px;
|
||||||
}
|
}
|
||||||
.icon.img {
|
.icon.img {
|
||||||
border: 1px solid rgba(238, 238, 238, 0.03);
|
border: 1px solid rgba(238, 238, 238, 0.03);
|
||||||
}
|
}
|
||||||
.actions {
|
.actions {
|
||||||
button {
|
button {
|
||||||
all: unset;
|
all: unset;
|
||||||
transition: all 500ms;
|
transition: all 500ms;
|
||||||
border-radius: 9px;
|
border-radius: 9px;
|
||||||
background-color: $background-color_3;
|
background-color: $background-color_3;
|
||||||
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03);
|
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03);
|
||||||
border-radius: 7.2px;
|
border-radius: 7.2px;
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
padding: 4.5px 9px;
|
padding: 4.5px 9px;
|
||||||
margin: 9px 4.5px 0;
|
margin: 9px 4.5px 0;
|
||||||
* {
|
* {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
&:focus {
|
&:focus {
|
||||||
box-shadow: inset 0 0 0 1px #51a4e7;
|
box-shadow: inset 0 0 0 1px #51a4e7;
|
||||||
background-color: $background-color_1;
|
background-color: $background-color_1;
|
||||||
}
|
}
|
||||||
&:hover {
|
&:hover {
|
||||||
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03);
|
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03);
|
||||||
background-color: $background-color_1;
|
background-color: $background-color_1;
|
||||||
}
|
}
|
||||||
&:active {
|
&:active {
|
||||||
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03);
|
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03);
|
||||||
background-image: linear-gradient(to right, #51a4e7, #6cb2eb);
|
background-image: linear-gradient(to right, #51a4e7, #6cb2eb);
|
||||||
background-color: $background-color_4;
|
background-color: $background-color_4;
|
||||||
&:hover {
|
&:hover {
|
||||||
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03), inset 0 0 0 99px rgba(238, 238, 238, 0.154);
|
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03), inset 0 0 0 99px rgba(238, 238, 238, 0.154);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&:checked {
|
&:checked {
|
||||||
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03);
|
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03);
|
||||||
background-image: linear-gradient(to right, #51a4e7, #6cb2eb);
|
background-image: linear-gradient(to right, #51a4e7, #6cb2eb);
|
||||||
background-color: $background-color_4;
|
background-color: $background-color_4;
|
||||||
&:hover {
|
&:hover {
|
||||||
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03), inset 0 0 0 99px rgba(238, 238, 238, 0.154);
|
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03), inset 0 0 0 99px rgba(238, 238, 238, 0.154);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&:disabled {
|
&:disabled {
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
background-color: $background-color_5;
|
background-color: $background-color_5;
|
||||||
}
|
}
|
||||||
&:first-child {
|
&:first-child {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
&:last-child {
|
&:last-child {
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
button.on {
|
button.on {
|
||||||
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03);
|
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03);
|
||||||
background-image: linear-gradient(to right, #51a4e7, #6cb2eb);
|
background-image: linear-gradient(to right, #51a4e7, #6cb2eb);
|
||||||
background-color: $background-color_4;
|
background-color: $background-color_4;
|
||||||
&:hover {
|
&:hover {
|
||||||
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03), inset 0 0 0 99px rgba(238, 238, 238, 0.154);
|
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03), inset 0 0 0 99px rgba(238, 238, 238, 0.154);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
button.active {
|
button.active {
|
||||||
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03);
|
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03);
|
||||||
background-image: linear-gradient(to right, #51a4e7, #6cb2eb);
|
background-image: linear-gradient(to right, #51a4e7, #6cb2eb);
|
||||||
background-color: $background-color_4;
|
background-color: $background-color_4;
|
||||||
&:hover {
|
&:hover {
|
||||||
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03), inset 0 0 0 99px rgba(238, 238, 238, 0.154);
|
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03), inset 0 0 0 99px rgba(238, 238, 238, 0.154);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
button.close-button {
|
button.close-button {
|
||||||
all: unset;
|
all: unset;
|
||||||
transition: all 500ms;
|
transition: all 500ms;
|
||||||
border-radius: 9px;
|
border-radius: 9px;
|
||||||
background-color: $background-color_5;
|
background-color: $background-color_5;
|
||||||
background-image: none;
|
background-image: none;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
margin-left: 9px;
|
margin-left: 9px;
|
||||||
border-radius: 7.2px;
|
border-radius: 7.2px;
|
||||||
min-width: 1.2em;
|
min-width: 1.2em;
|
||||||
min-height: 1.2em;
|
min-height: 1.2em;
|
||||||
* {
|
* {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
&:focus {
|
&:focus {
|
||||||
box-shadow: inset 0 0 0 1px #51a4e7;
|
box-shadow: inset 0 0 0 1px #51a4e7;
|
||||||
background-color: $background-color_1;
|
background-color: $background-color_1;
|
||||||
}
|
}
|
||||||
&:hover {
|
&:hover {
|
||||||
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03);
|
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03);
|
||||||
background-color: $background-color_1;
|
background-color: $background-color_1;
|
||||||
background-color: $background-color_2;
|
background-color: $background-color_2;
|
||||||
}
|
}
|
||||||
&:active {
|
&:active {
|
||||||
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03);
|
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03);
|
||||||
background-image: linear-gradient(to right, #51a4e7, #6cb2eb);
|
background-image: linear-gradient(to right, #51a4e7, #6cb2eb);
|
||||||
background-color: $background-color_4;
|
background-color: $background-color_4;
|
||||||
background-image: linear-gradient(#e67090, #e67090);
|
background-image: linear-gradient(#e67090, #e67090);
|
||||||
&:hover {
|
&:hover {
|
||||||
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03), inset 0 0 0 99px rgba(238, 238, 238, 0.154);
|
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03), inset 0 0 0 99px rgba(238, 238, 238, 0.154);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&:checked {
|
&:checked {
|
||||||
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03);
|
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03);
|
||||||
background-image: linear-gradient(to right, #51a4e7, #6cb2eb);
|
background-image: linear-gradient(to right, #51a4e7, #6cb2eb);
|
||||||
background-color: $background-color_4;
|
background-color: $background-color_4;
|
||||||
&:hover {
|
&:hover {
|
||||||
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03), inset 0 0 0 99px rgba(238, 238, 238, 0.154);
|
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03), inset 0 0 0 99px rgba(238, 238, 238, 0.154);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&:disabled {
|
&:disabled {
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
background-color: $background-color_5;
|
background-color: $background-color_5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
button.close-button.on {
|
button.close-button.on {
|
||||||
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03);
|
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03);
|
||||||
background-image: linear-gradient(to right, #51a4e7, #6cb2eb);
|
background-image: linear-gradient(to right, #51a4e7, #6cb2eb);
|
||||||
background-color: $background-color_4;
|
background-color: $background-color_4;
|
||||||
&:hover {
|
&:hover {
|
||||||
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03), inset 0 0 0 99px rgba(238, 238, 238, 0.154);
|
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03), inset 0 0 0 99px rgba(238, 238, 238, 0.154);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
button.close-button.active {
|
button.close-button.active {
|
||||||
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03);
|
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03);
|
||||||
background-image: linear-gradient(to right, #51a4e7, #6cb2eb);
|
background-image: linear-gradient(to right, #51a4e7, #6cb2eb);
|
||||||
background-color: $background-color_4;
|
background-color: $background-color_4;
|
||||||
&:hover {
|
&:hover {
|
||||||
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03), inset 0 0 0 99px rgba(238, 238, 238, 0.154);
|
box-shadow: inset 0 0 0 1px rgba(238, 238, 238, 0.03), inset 0 0 0 99px rgba(238, 238, 238, 0.154);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,88 +4,87 @@ import { Service, Utils } from '../imports.js';
|
||||||
|
|
||||||
|
|
||||||
class Pointers extends Service {
|
class Pointers extends Service {
|
||||||
static {
|
static {
|
||||||
Service.register(this, {
|
Service.register(this, {
|
||||||
'proc-started': ['boolean'],
|
'proc-started': ['boolean'],
|
||||||
'proc-destroyed': ['boolean'],
|
'proc-destroyed': ['boolean'],
|
||||||
'device-fetched': ['boolean'],
|
'device-fetched': ['boolean'],
|
||||||
'new-line': ['string'],
|
'new-line': ['string'],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
proc = undefined;
|
proc = undefined;
|
||||||
output = "";
|
output = '';
|
||||||
devices = new Map();
|
devices = new Map();
|
||||||
|
|
||||||
get proc() { return this.proc; }
|
get process() { return this.proc; }
|
||||||
get output() { return this.output; }
|
get lastLine() { return this.output; }
|
||||||
get devices() { return this.devices; }
|
get pointers() { return this.devices; }
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.parseDevices();
|
this.parseDevices();
|
||||||
}
|
}
|
||||||
|
|
||||||
parseDevices() {
|
parseDevices() {
|
||||||
Utils.execAsync(['libinput', 'list-devices']).then(out => {
|
Utils.execAsync(['libinput', 'list-devices']).then(out => {
|
||||||
let lines = out.split('\n');
|
const lines = out.split('\n');
|
||||||
let device = null;
|
let device = null;
|
||||||
let devices = new Map();
|
const devices = new Map();
|
||||||
|
|
||||||
lines.forEach(line => {
|
lines.forEach(line => {
|
||||||
let parts = line.split(':');
|
const parts = line.split(':');
|
||||||
|
|
||||||
if (parts[0] === 'Device') {
|
if (parts[0] === 'Device') {
|
||||||
device = {};
|
device = {};
|
||||||
devices.set(parts[1].trim(), device);
|
devices.set(parts[1].trim(), device);
|
||||||
}
|
}
|
||||||
else if (device && parts[1]) {
|
else if (device && parts[1]) {
|
||||||
let key = parts[0].trim();
|
const key = parts[0].trim();
|
||||||
let value = parts[1].trim();
|
const value = parts[1].trim();
|
||||||
device[key] = value;
|
device[key] = value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.devices = Array.from(devices).filter(dev => dev.Capabilities &&
|
this.devices = Array.from(devices).filter(dev => dev.Capabilities &&
|
||||||
dev.Capabilities.includes('pointer'));
|
dev.Capabilities.includes('pointer'));
|
||||||
this.emit('device-fetched', true);
|
this.emit('device-fetched', true);
|
||||||
}).catch(print);
|
}).catch(print);
|
||||||
}
|
}
|
||||||
|
|
||||||
startProc() {
|
startProc() {
|
||||||
if (this.proc)
|
if (this.proc)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let args = [];
|
const args = [];
|
||||||
this.devices.forEach(dev => {
|
this.devices.forEach(dev => {
|
||||||
if (dev.Kernel) {
|
if (dev.Kernel) {
|
||||||
args.push('--device');
|
args.push('--device');
|
||||||
args.push(dev.Kernel);
|
args.push(dev.Kernel);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.proc = Utils.subprocess(
|
this.proc = Utils.subprocess(
|
||||||
['libinput', 'debug-events', ...args],
|
['libinput', 'debug-events', ...args],
|
||||||
(output) => {
|
output => {
|
||||||
if (output.includes('BTN') && output.includes('released') ||
|
if (output.includes('BTN') && output.includes('released') ||
|
||||||
output.includes('TOUCH_UP') ||
|
output.includes('TOUCH_UP') ||
|
||||||
output.includes('HOLD_END') && !output.includes('cancelled')) {
|
output.includes('HOLD_END') && !output.includes('cancelled')) {
|
||||||
|
this.output = output;
|
||||||
this.output = 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.proc) {
|
this.proc.force_exit();
|
||||||
this.proc.force_exit();
|
this.proc = undefined;
|
||||||
this.proc = undefined;
|
this.emit('proc-destroyed', true);
|
||||||
this.emit('proc-destroyed', true);
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const pointersService = new Pointers();
|
const pointersService = new Pointers();
|
||||||
|
|
Loading…
Reference in a new issue