feat(hypr): replace ags overview with hycov
All checks were successful
Discord / discord commits (push) Has been skipped
All checks were successful
Discord / discord commits (push) Has been skipped
This commit is contained in:
parent
6a880378fe
commit
540db27873
20 changed files with 242 additions and 924 deletions
|
@ -1,29 +1,9 @@
|
|||
plugin {
|
||||
touch_gestures {
|
||||
# The default sensitivity is probably too low on tablet screens,
|
||||
# I recommend turning it up to 4.0
|
||||
sensitivity = 4.0
|
||||
|
||||
# must be >= 3
|
||||
workspace_swipe_fingers = 3
|
||||
|
||||
experimental {
|
||||
# send proper cancel events to windows instead of hacky touch_up events,
|
||||
# NOT recommended as it crashed a few times, once it's stabilized I'll make it the default
|
||||
send_cancel = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Autostart programs
|
||||
exec-once = sleep 3; nextcloud --background
|
||||
exec-once = squeekboard
|
||||
exec-once = ags
|
||||
exec-once = sleep 3; ags -t applauncher
|
||||
|
||||
## Change HandleLidSwitch to lock in logind.conf
|
||||
exec-once = swayidle -w lock lock
|
||||
|
||||
## Special window apps
|
||||
exec-once = [workspace special:thunder silent] thunderbird
|
||||
windowrule = workspace special:thunder silent,^(thunderbird)$
|
||||
|
@ -40,12 +20,6 @@ device:razer-razer-naga-pro-1 {
|
|||
accel_profile = "flat"
|
||||
}
|
||||
|
||||
gestures {
|
||||
workspace_swipe = yes
|
||||
workspace_swipe_fingers = 3
|
||||
workspace_swipe_cancel_ratio = 0.15
|
||||
}
|
||||
|
||||
|
||||
# Binds
|
||||
|
||||
|
@ -58,7 +32,6 @@ bindr = CAPS, Caps_Lock, exec, ags -r 'Brightness.fetchCapsState()'
|
|||
bindn = , Escape, exec, ags run-js 'closeAll()'
|
||||
bind = $mainMod SHIFT, E , exec, ags -t powermenu
|
||||
bind = $mainMod , D , exec, ags -t applauncher
|
||||
bind = ALT , Tab , exec, ags -t overview
|
||||
|
||||
|
||||
# Cosmetic
|
||||
|
|
BIN
flake.lock
BIN
flake.lock
Binary file not shown.
BIN
flake.nix
BIN
flake.nix
Binary file not shown.
|
@ -1,20 +0,0 @@
|
|||
{...}: {
|
||||
dconf.settings = {
|
||||
"org/virt-manager/virt-manager/connections" = {
|
||||
autoconnect = ["qemu:///system"];
|
||||
uris = ["qemu:///system"];
|
||||
};
|
||||
|
||||
"apps/seahorse/listing" = {
|
||||
keyrings-selected = ["gnupg://"];
|
||||
};
|
||||
|
||||
"org/gtk/settings/file-chooser" = {
|
||||
show-hidden = true;
|
||||
};
|
||||
|
||||
"org/gnome/desktop/interface" = {
|
||||
color-scheme = "prefer-dark";
|
||||
};
|
||||
};
|
||||
}
|
|
@ -8,7 +8,7 @@ import Powermenu from './ts/powermenu.ts';
|
|||
const closeWinDelay = 800;
|
||||
|
||||
|
||||
// TODO: add OSD, workspace indicator / overview and current window indicator
|
||||
// TODO: add OSD, workspace indicator and current window indicator
|
||||
export default {
|
||||
onConfigParsed: () => {
|
||||
globalThis.Pointers = Pointers;
|
||||
|
|
|
@ -1,53 +0,0 @@
|
|||
.overview {
|
||||
background-color: rgba($bgfull, 0.4);
|
||||
border: 2px solid $contrast-bg;
|
||||
border-radius: 10px;
|
||||
|
||||
.workspace {
|
||||
padding: 4px 15px 4px 0;
|
||||
border: 2px solid transparent;
|
||||
border-radius: 10px;
|
||||
|
||||
&.active {
|
||||
background-color: rgba(lighten($color: black, $amount: 15), 0.8);
|
||||
border: 2px solid black;
|
||||
}
|
||||
}
|
||||
|
||||
.workspace .window {
|
||||
background-color: $bgfull;
|
||||
border-radius: 10px;
|
||||
margin: 0 10px;
|
||||
transition: min-width 0.2s ease-in-out,
|
||||
min-height 0.2s ease-in-out,
|
||||
border-color 0.2s ease-in-out,
|
||||
font-size 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.normal {
|
||||
margin-bottom: 5px;
|
||||
|
||||
.workspace {
|
||||
.window {
|
||||
border: 2px solid #411C6C;
|
||||
|
||||
&.active {
|
||||
border: 2px solid purple;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.special {
|
||||
.workspace {
|
||||
.window {
|
||||
border: 2px solid lighten($color: black, $amount: 20);
|
||||
|
||||
&.active {
|
||||
border: 2px solid purple;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,7 +18,6 @@ undershoot {
|
|||
@import "./wim-widgets/date";
|
||||
@import "./wim-widgets/quick-settings";
|
||||
@import "./wim-widgets/player";
|
||||
@import "./wim-widgets/overview";
|
||||
@import "./wim-widgets/applauncher";
|
||||
@import "./wim-widgets/osd";
|
||||
@import "./wim-widgets/osk";
|
||||
|
|
|
@ -1,197 +0,0 @@
|
|||
const Hyprland = await Service.import('hyprland');
|
||||
|
||||
const { Icon, Revealer } = Widget;
|
||||
const { timeout } = Utils;
|
||||
|
||||
import { WindowButton } from './dragndrop.ts';
|
||||
import * as VARS from './variables.ts';
|
||||
|
||||
// Types
|
||||
import { Client as HyprClient } from 'types/service/hyprland.ts';
|
||||
import AgsRevealer from 'types/widgets/revealer.ts';
|
||||
import AgsBox from 'types/widgets/box.ts';
|
||||
import AgsButton from 'types/widgets/button.ts';
|
||||
import AgsIcon from 'types/widgets/icon.ts';
|
||||
|
||||
const scale = (size: number) => (size * VARS.SCALE) - VARS.MARGIN;
|
||||
|
||||
const getFontSize = (client: HyprClient) => {
|
||||
const valX = scale(client.size[0]) * VARS.ICON_SCALE;
|
||||
const valY = scale(client.size[1]) * VARS.ICON_SCALE;
|
||||
|
||||
const size = Math.min(valX, valY);
|
||||
|
||||
return size <= 0 ? 0.1 : size;
|
||||
};
|
||||
|
||||
const IconStyle = (client: HyprClient) => `
|
||||
min-width: ${scale(client.size[0])}px;
|
||||
min-height: ${scale(client.size[1])}px;
|
||||
font-size: ${getFontSize(client)}px;
|
||||
`;
|
||||
|
||||
|
||||
const Client = (
|
||||
client: HyprClient,
|
||||
active: boolean,
|
||||
clients: Array<HyprClient>,
|
||||
box: AgsBox,
|
||||
) => {
|
||||
const wsName = String(client.workspace.name).replace('special:', '');
|
||||
const wsId = client.workspace.id;
|
||||
const addr = `address:${client.address}`;
|
||||
|
||||
return Revealer({
|
||||
transition: 'crossfade',
|
||||
reveal_child: true,
|
||||
|
||||
attribute: {
|
||||
address: client.address,
|
||||
to_destroy: false,
|
||||
},
|
||||
|
||||
child: WindowButton({
|
||||
mainBox: box,
|
||||
address: client.address,
|
||||
|
||||
on_secondary_click_release: () => {
|
||||
Hyprland.sendMessage(`dispatch closewindow ${addr}`);
|
||||
},
|
||||
|
||||
on_primary_click_release: () => {
|
||||
if (wsId < 0) {
|
||||
if (client.workspace.name === 'special') {
|
||||
Hyprland.sendMessage('dispatch ' +
|
||||
`movetoworkspacesilent special:${wsId},${addr}`)
|
||||
.then(() => {
|
||||
Hyprland.sendMessage('dispatch ' +
|
||||
`togglespecialworkspace ${wsId}`)
|
||||
.then(() => {
|
||||
App.closeWindow('overview');
|
||||
}).catch(print);
|
||||
}).catch(print);
|
||||
}
|
||||
else {
|
||||
Hyprland.sendMessage('dispatch ' +
|
||||
`togglespecialworkspace ${wsName}`)
|
||||
.then(() => {
|
||||
App.closeWindow('overview');
|
||||
}).catch(print);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Close special workspace if one is opened
|
||||
const activeAddress = Hyprland.active.client.address;
|
||||
|
||||
const currentActive = clients.find((c) => {
|
||||
return c.address === activeAddress;
|
||||
});
|
||||
|
||||
if (currentActive && currentActive.workspace.id < 0) {
|
||||
const currentSpecial = `${currentActive.workspace.name}`
|
||||
.replace('special:', '');
|
||||
|
||||
Hyprland.sendMessage('dispatch ' +
|
||||
`togglespecialworkspace ${currentSpecial}`)
|
||||
.catch(print);
|
||||
}
|
||||
|
||||
Hyprland.sendMessage(`dispatch focuswindow ${addr}`)
|
||||
.then(() => {
|
||||
App.closeWindow('overview');
|
||||
}).catch(print);
|
||||
}
|
||||
},
|
||||
|
||||
child: Icon({
|
||||
class_name: `window ${active ? 'active' : ''}`,
|
||||
css: `${IconStyle(client)} font-size: 10px;`,
|
||||
icon: client.class,
|
||||
}),
|
||||
}),
|
||||
});
|
||||
};
|
||||
|
||||
export const updateClients = (box: AgsBox) => {
|
||||
Hyprland.sendMessage('j/clients').then((out) => {
|
||||
let clients = JSON.parse(out) as Array<HyprClient>;
|
||||
|
||||
clients = clients.filter((client) => client.class);
|
||||
|
||||
box.attribute.workspaces.forEach(
|
||||
(workspace: AgsRevealer) => {
|
||||
const fixed = workspace.attribute.get_fixed();
|
||||
const toRemove = fixed.get_children() as Array<AgsRevealer>;
|
||||
|
||||
clients.filter((client) =>
|
||||
client.workspace.id === workspace.attribute.id)
|
||||
.forEach((client) => {
|
||||
const active =
|
||||
client.address === Hyprland.active.client.address;
|
||||
|
||||
// TODO: see if this works on multi monitor setup
|
||||
const alloc = box.get_allocation();
|
||||
let monitor = box.get_display()
|
||||
.get_monitor_at_point(alloc.x, alloc.y);
|
||||
|
||||
monitor = Hyprland.monitors.find((mon) => {
|
||||
return mon.make === monitor.manufacturer &&
|
||||
mon.model === monitor.model;
|
||||
});
|
||||
|
||||
client.at[0] -= monitor.x;
|
||||
client.at[1] -= monitor.y;
|
||||
|
||||
// Special workspaces that haven't been opened yet
|
||||
// return a size of 0. We need to set them to default
|
||||
// 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;
|
||||
}
|
||||
|
||||
const newClient = [
|
||||
(fixed.get_children() as Array<AgsRevealer>)
|
||||
.find((ch) =>
|
||||
ch.attribute.address === client.address),
|
||||
client.at[0] * VARS.SCALE,
|
||||
client.at[1] * VARS.SCALE,
|
||||
] as [AgsRevealer, number, number];
|
||||
|
||||
// If it exists already
|
||||
if (newClient[0]) {
|
||||
toRemove.splice(toRemove.indexOf(newClient[0]), 1);
|
||||
fixed.move(...newClient);
|
||||
}
|
||||
else {
|
||||
newClient[0] = Client(client, active, clients, box);
|
||||
fixed.put(...newClient);
|
||||
}
|
||||
|
||||
// Set a timeout here to have an animation when the icon first appears
|
||||
timeout(1, () => {
|
||||
((newClient[0].child as AgsButton)
|
||||
.child as AgsIcon)
|
||||
.class_name = `window ${active}`;
|
||||
|
||||
((newClient[0].child as AgsButton)
|
||||
.child as AgsIcon).setCss(IconStyle(client));
|
||||
});
|
||||
});
|
||||
|
||||
fixed.show_all();
|
||||
toRemove.forEach((ch) => {
|
||||
if (ch.attribute.to_destroy) {
|
||||
ch.destroy();
|
||||
}
|
||||
else {
|
||||
ch.reveal_child = false;
|
||||
ch.attribute.to_destroy = true;
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
}).catch(print);
|
||||
};
|
|
@ -1,51 +0,0 @@
|
|||
const Hyprland = await Service.import('hyprland');
|
||||
|
||||
const { Box } = Widget;
|
||||
|
||||
import * as VARS from './variables.ts';
|
||||
|
||||
const PADDING = 34;
|
||||
const MARGIN = 9;
|
||||
const DEFAULT_STYLE = `
|
||||
min-width: ${VARS.SCREEN.X * VARS.SCALE}px;
|
||||
min-height: ${(VARS.SCREEN.Y * VARS.SCALE) - (VARS.MARGIN / 2)}px;
|
||||
border-radius: 10px;
|
||||
`;
|
||||
|
||||
// Types
|
||||
import AgsBox from 'types/widgets/box.ts';
|
||||
import AgsRevealer from 'types/widgets/revealer.ts';
|
||||
import AgsCenterBox from 'types/widgets/centerbox.ts';
|
||||
import AgsEventBox from 'types/widgets/eventbox.ts';
|
||||
|
||||
|
||||
export const Highlighter = () => Box({
|
||||
vpack: 'start',
|
||||
hpack: 'start',
|
||||
class_name: 'workspace active',
|
||||
css: DEFAULT_STYLE,
|
||||
});
|
||||
|
||||
export const updateCurrentWorkspace = (main: AgsBox, highlighter: AgsBox) => {
|
||||
const currentId = Hyprland.active.workspace.id;
|
||||
const row = Math.floor((currentId - 1) / VARS.WORKSPACE_PER_ROW);
|
||||
|
||||
const rowObject = (main.children[0] as AgsBox).children[row] as AgsRevealer;
|
||||
const workspaces = ((((rowObject.child as AgsCenterBox)
|
||||
.center_widget as AgsEventBox)
|
||||
.child as AgsBox)
|
||||
.get_children() as Array<AgsRevealer>)
|
||||
.filter((w) => w.reveal_child);
|
||||
|
||||
const currentIndex = workspaces.findIndex(
|
||||
(w) => w.attribute.id === currentId,
|
||||
);
|
||||
const left = currentIndex * ((VARS.SCREEN.X * VARS.SCALE) + 2 + PADDING);
|
||||
const height = row * ((VARS.SCREEN.Y * VARS.SCALE) + (PADDING / 2));
|
||||
|
||||
highlighter.setCss(`
|
||||
${DEFAULT_STYLE}
|
||||
margin-left: ${MARGIN + left}px;
|
||||
margin-top: ${MARGIN + height}px;
|
||||
`);
|
||||
};
|
|
@ -1,122 +0,0 @@
|
|||
const Hyprland = await Service.import('hyprland');
|
||||
|
||||
const { Button, EventBox } = Widget;
|
||||
|
||||
import Cairo from 'cairo';
|
||||
const { Gtk, Gdk } = imports.gi;
|
||||
|
||||
import { updateClients } from './clients.ts';
|
||||
|
||||
const TARGET = [Gtk.TargetEntry.new('text/plain', Gtk.TargetFlags.SAME_APP, 0)];
|
||||
const display = Gdk.Display.get_default();
|
||||
|
||||
// Types
|
||||
import AgsBox from 'types/widgets/box.ts';
|
||||
import AgsButton from 'types/widgets/button.ts';
|
||||
import AgsRevealer from 'types/widgets/revealer.ts';
|
||||
import { ButtonProps } from 'types/widgets/button.ts';
|
||||
import { EventBoxProps } from 'types/widgets/eventbox.ts';
|
||||
type WindowButtonType = ButtonProps & {
|
||||
address: string
|
||||
mainBox: AgsBox
|
||||
};
|
||||
|
||||
|
||||
const createSurfaceFromWidget = (widget: AgsButton) => {
|
||||
const alloc = widget.get_allocation();
|
||||
const surface = new Cairo.ImageSurface(
|
||||
Cairo.Format.ARGB32,
|
||||
alloc.width,
|
||||
alloc.height,
|
||||
);
|
||||
const cr = new Cairo.Context(surface);
|
||||
|
||||
cr.setSourceRGBA(255, 255, 255, 0);
|
||||
cr.rectangle(0, 0, alloc.width, alloc.height);
|
||||
cr.fill();
|
||||
widget.draw(cr);
|
||||
|
||||
return surface;
|
||||
};
|
||||
|
||||
let hidden = 0;
|
||||
|
||||
export const WorkspaceDrop = ({ ...props }: EventBoxProps) => EventBox({
|
||||
...props,
|
||||
setup: (self) => {
|
||||
self.drag_dest_set(Gtk.DestDefaults.ALL, TARGET, Gdk.DragAction.COPY);
|
||||
|
||||
self.on('drag-data-received', (_, _c, _x, _y, data) => {
|
||||
let id = (self.get_parent() as AgsRevealer)?.attribute.id;
|
||||
|
||||
if (id < -1) {
|
||||
id = (self.get_parent() as AgsRevealer)?.attribute.name;
|
||||
}
|
||||
|
||||
else if (id === -1) {
|
||||
id = `special:${++hidden}`;
|
||||
}
|
||||
|
||||
else if (id === 1000) {
|
||||
id = 'empty';
|
||||
}
|
||||
|
||||
Hyprland.sendMessage('dispatch ' +
|
||||
`movetoworkspacesilent ${id},address:${data.get_text()}`)
|
||||
.catch(print);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export const WindowButton = ({
|
||||
address,
|
||||
mainBox,
|
||||
...props
|
||||
}: WindowButtonType) => Button({
|
||||
...props,
|
||||
|
||||
setup: (self) => {
|
||||
self.drag_source_set(
|
||||
Gdk.ModifierType.BUTTON1_MASK,
|
||||
TARGET,
|
||||
Gdk.DragAction.COPY,
|
||||
);
|
||||
|
||||
self
|
||||
.on('drag-data-get', (_w, _c, data) => {
|
||||
data.set_text(address, address.length);
|
||||
})
|
||||
|
||||
.on('drag-begin', (_, context) => {
|
||||
Gtk.drag_set_icon_surface(
|
||||
context,
|
||||
createSurfaceFromWidget(self),
|
||||
);
|
||||
(self.get_parent() as AgsRevealer)?.set_reveal_child(false);
|
||||
})
|
||||
|
||||
.on('drag-end', () => {
|
||||
self.get_parent()?.destroy();
|
||||
|
||||
updateClients(mainBox);
|
||||
})
|
||||
|
||||
// OnHover
|
||||
.on('enter-notify-event', () => {
|
||||
if (!display) {
|
||||
return;
|
||||
}
|
||||
self.window.set_cursor(Gdk.Cursor.new_from_name(
|
||||
display,
|
||||
'pointer',
|
||||
));
|
||||
self.toggleClassName('hover', true);
|
||||
})
|
||||
|
||||
// OnHoverLost
|
||||
.on('leave-notify-event', () => {
|
||||
self.window.set_cursor(null);
|
||||
self.toggleClassName('hover', false);
|
||||
});
|
||||
},
|
||||
});
|
|
@ -1,151 +0,0 @@
|
|||
const Hyprland = await Service.import('hyprland');
|
||||
|
||||
const { Box, Overlay, Window } = Widget;
|
||||
|
||||
import { WorkspaceRow, getWorkspaces, updateWorkspaces } from './workspaces.ts';
|
||||
import { Highlighter, updateCurrentWorkspace } from './current-workspace.ts';
|
||||
import { updateClients } from './clients.ts';
|
||||
|
||||
// Types
|
||||
import AgsBox from 'types/widgets/box.ts';
|
||||
import AgsOverlay from 'types/widgets/overlay.ts';
|
||||
|
||||
|
||||
// TODO: have a 'page' for each monitor, arrows on both sides to loop through
|
||||
export const Overview = () => {
|
||||
const highlighter = Highlighter();
|
||||
|
||||
const mainBox = Box({
|
||||
// Do this for scss hierarchy
|
||||
class_name: 'overview',
|
||||
css: 'all: unset',
|
||||
|
||||
vertical: true,
|
||||
vpack: 'center',
|
||||
hpack: 'center',
|
||||
|
||||
attribute: {
|
||||
workspaces: [],
|
||||
|
||||
update: () => {
|
||||
getWorkspaces(mainBox);
|
||||
updateWorkspaces(mainBox);
|
||||
updateClients(mainBox);
|
||||
updateCurrentWorkspace(mainBox, highlighter);
|
||||
},
|
||||
},
|
||||
|
||||
children: [
|
||||
Box({
|
||||
vertical: true,
|
||||
children: [
|
||||
WorkspaceRow('normal', 0),
|
||||
],
|
||||
}),
|
||||
|
||||
Box({
|
||||
vertical: true,
|
||||
children: [
|
||||
WorkspaceRow('special', 0),
|
||||
],
|
||||
}),
|
||||
],
|
||||
|
||||
setup: (self) => {
|
||||
self.hook(Hyprland, () => {
|
||||
if (!App.getWindow('overview')?.visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.attribute.update();
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const widget = Overlay({
|
||||
overlays: [highlighter, mainBox],
|
||||
|
||||
attribute: {
|
||||
get_child: () => mainBox,
|
||||
closing: false,
|
||||
},
|
||||
|
||||
// Make size of overlay big enough for content
|
||||
child: Box({
|
||||
class_name: 'overview',
|
||||
css: `
|
||||
min-height: ${mainBox.get_allocated_height()}px;
|
||||
min-width: ${mainBox.get_allocated_width()}px;
|
||||
`,
|
||||
}),
|
||||
|
||||
// TODO: throttle this?
|
||||
setup: (self) => {
|
||||
self.on('get-child-position', (_, ch) => {
|
||||
if (ch === mainBox && !self.attribute.closing) {
|
||||
(self.child as AgsBox).setCss(`
|
||||
transition: min-height 0.2s ease, min-width 0.2s ease;
|
||||
min-height: ${mainBox.get_allocated_height()}px;
|
||||
min-width: ${mainBox.get_allocated_width()}px;
|
||||
`);
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
return widget;
|
||||
};
|
||||
|
||||
// FIXME: can't use PopupWindow because this is an overlay already
|
||||
export default () => {
|
||||
const transition_duration = 800;
|
||||
const win = Window({
|
||||
name: 'overview',
|
||||
visible: false,
|
||||
|
||||
// Needs this to have space
|
||||
// allocated at the start
|
||||
child: Box({
|
||||
css: `
|
||||
min-height: 1px;
|
||||
min-width: 1px;
|
||||
padding: 1px;
|
||||
`,
|
||||
}),
|
||||
|
||||
attribute: { close_on_unfocus: 'none' },
|
||||
|
||||
setup: (self) => {
|
||||
const name = 'overview';
|
||||
|
||||
Hyprland.sendMessage('[[BATCH]] ' +
|
||||
`keyword layerrule ignorealpha[0.97],${name}; ` +
|
||||
`keyword layerrule blur,${name}`);
|
||||
|
||||
self.hook(App, (_, currentName, isOpen) => {
|
||||
if (currentName === self.name) {
|
||||
if (isOpen) {
|
||||
self.child = Overview();
|
||||
self.show_all();
|
||||
|
||||
(self.child as AgsOverlay)
|
||||
.attribute.get_child().attribute.update();
|
||||
}
|
||||
else {
|
||||
(self.child as AgsOverlay).attribute.closing = true;
|
||||
|
||||
((self.child as AgsOverlay)
|
||||
.child as AgsBox).css = `
|
||||
min-height: 1px;
|
||||
min-width: 1px;
|
||||
transition: all
|
||||
${transition_duration - 10}ms ease;
|
||||
`;
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
return win;
|
||||
};
|
|
@ -1,14 +0,0 @@
|
|||
export const SCALE = 0.11;
|
||||
export const ICON_SCALE = 0.8;
|
||||
export const MARGIN = 8;
|
||||
export const DEFAULT_SPECIAL = {
|
||||
SIZE_X: 1524,
|
||||
SIZE_Y: 908,
|
||||
POS_X: 197,
|
||||
POS_Y: 170,
|
||||
};
|
||||
export const WORKSPACE_PER_ROW = 6;
|
||||
export const SCREEN = {
|
||||
X: 1920,
|
||||
Y: 1200,
|
||||
};
|
|
@ -1,202 +0,0 @@
|
|||
const Hyprland = await Service.import('hyprland');
|
||||
|
||||
const { Revealer, CenterBox, Box, EventBox, Fixed, Label } = Widget;
|
||||
|
||||
import { WorkspaceDrop } from './dragndrop.ts';
|
||||
import * as VARS from './variables.ts';
|
||||
|
||||
const EMPTY_OFFSET = 16;
|
||||
const DEFAULT_STYLE = `
|
||||
min-width: ${(VARS.SCREEN.X * VARS.SCALE) + EMPTY_OFFSET}px;
|
||||
min-height: ${VARS.SCREEN.Y * VARS.SCALE}px;
|
||||
`;
|
||||
|
||||
// Types
|
||||
import AgsBox from 'types/widgets/box.ts';
|
||||
import AgsRevealer from 'types/widgets/revealer.ts';
|
||||
import AgsCenterBox from 'types/widgets/centerbox.ts';
|
||||
import AgsEventBox from 'types/widgets/eventbox.ts';
|
||||
|
||||
|
||||
export const getWorkspaces = (box: AgsBox) => {
|
||||
const children = [] as Array<AgsRevealer>;
|
||||
|
||||
(box.children as Array<AgsBox>).forEach((type) => {
|
||||
(type.children as Array<AgsRevealer>).forEach(
|
||||
(row) => {
|
||||
((((row.child as AgsCenterBox)
|
||||
.center_widget as AgsEventBox)
|
||||
.child as AgsBox)
|
||||
.children as Array<AgsRevealer>)
|
||||
.forEach((workspace) => {
|
||||
children.push(workspace);
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
box.attribute.workspaces = children.sort((a, b) => {
|
||||
return a.attribute.id - b.attribute.id;
|
||||
});
|
||||
};
|
||||
|
||||
const Workspace = (id: number, name: string, normal = true) => {
|
||||
// @ts-expect-error
|
||||
const fixed = Fixed();
|
||||
|
||||
const workspace = Revealer({
|
||||
transition: 'slide_right',
|
||||
transition_duration: 500,
|
||||
|
||||
attribute: {
|
||||
id,
|
||||
name,
|
||||
get_fixed: () => fixed,
|
||||
},
|
||||
|
||||
setup: (self) => {
|
||||
if (normal) {
|
||||
self.hook(Hyprland, () => {
|
||||
const activeId = Hyprland.active.workspace.id;
|
||||
const active = activeId === self.attribute.id;
|
||||
const ws = Hyprland.getWorkspace(self.attribute.id);
|
||||
|
||||
self.reveal_child =
|
||||
(ws?.windows && ws.windows > 0) || active;
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
child: WorkspaceDrop({
|
||||
child: Box({
|
||||
class_name: 'workspace',
|
||||
css: normal ?
|
||||
|
||||
DEFAULT_STYLE :
|
||||
|
||||
`
|
||||
min-width: ${(VARS.SCREEN.X * VARS.SCALE / 2) +
|
||||
EMPTY_OFFSET}px;
|
||||
min-height: ${VARS.SCREEN.Y * VARS.SCALE}px;
|
||||
`,
|
||||
|
||||
children: normal ?
|
||||
|
||||
[fixed] :
|
||||
|
||||
[
|
||||
fixed,
|
||||
Label({
|
||||
label: ' +',
|
||||
css: 'font-size: 40px;',
|
||||
}),
|
||||
],
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
return workspace;
|
||||
};
|
||||
|
||||
export const WorkspaceRow = (class_name: string, i: number) => {
|
||||
const addWorkspace = Workspace(
|
||||
class_name === 'special' ? -1 : 1000,
|
||||
class_name === 'special' ? 'special' : '',
|
||||
false,
|
||||
);
|
||||
|
||||
return Revealer({
|
||||
transition: 'slide_down',
|
||||
hpack: class_name === 'special' ? 'fill' : 'start',
|
||||
|
||||
setup: (self) => {
|
||||
self.hook(Hyprland, (rev) => {
|
||||
const minId = i * VARS.WORKSPACE_PER_ROW;
|
||||
const activeId = Hyprland.active.workspace.id;
|
||||
|
||||
const rowExists = Hyprland.workspaces.some((ws) => {
|
||||
const isInRow = ws.id > minId;
|
||||
const hasClients = ws.windows > 0;
|
||||
const isActive = ws.id === activeId;
|
||||
|
||||
return isInRow && (hasClients || isActive);
|
||||
});
|
||||
|
||||
rev.reveal_child = rowExists;
|
||||
});
|
||||
},
|
||||
|
||||
child: CenterBox({
|
||||
center_widget: EventBox({
|
||||
setup: (self) => {
|
||||
self.hook(Hyprland, () => {
|
||||
const maxId = (i + 1) * VARS.WORKSPACE_PER_ROW;
|
||||
const activeId = Hyprland.active.workspace.id;
|
||||
|
||||
const isSpecial = class_name === 'special';
|
||||
const nextRowExists = Hyprland.workspaces.some((ws) => {
|
||||
const isInNextRow = ws.id > maxId;
|
||||
const hasClients = ws.windows > 0;
|
||||
const isActive = ws.id === activeId;
|
||||
|
||||
return isInNextRow && (hasClients || isActive);
|
||||
});
|
||||
|
||||
addWorkspace.reveal_child = isSpecial || !nextRowExists;
|
||||
});
|
||||
},
|
||||
|
||||
child: Box({
|
||||
class_name,
|
||||
children: [addWorkspace],
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
});
|
||||
};
|
||||
|
||||
export const updateWorkspaces = (box: AgsBox) => {
|
||||
Hyprland.workspaces.forEach((ws) => {
|
||||
const currentWs = (box.attribute.workspaces as Array<AgsRevealer>).find(
|
||||
(ch) => ch.attribute.id === ws.id,
|
||||
);
|
||||
|
||||
if (!currentWs) {
|
||||
let type = 0;
|
||||
let rowNo = 0;
|
||||
|
||||
if (ws.id < 0) {
|
||||
// This means it's a special workspace
|
||||
type = 1;
|
||||
}
|
||||
else {
|
||||
rowNo = Math.floor((ws.id - 1) / VARS.WORKSPACE_PER_ROW);
|
||||
const wsRow = box.children[type] as AgsBox;
|
||||
const wsQty = wsRow.children.length;
|
||||
|
||||
if (rowNo >= wsQty) {
|
||||
for (let i = wsQty; i <= rowNo; ++i) {
|
||||
wsRow.add(WorkspaceRow(
|
||||
type ? 'special' : 'normal', i,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
const row = ((((box.children[type] as AgsBox)
|
||||
.children[rowNo] as AgsRevealer)
|
||||
.child as AgsCenterBox)
|
||||
.center_widget as AgsEventBox)
|
||||
.child as AgsBox;
|
||||
|
||||
row.add(Workspace(ws.id, type ? ws.name : ''));
|
||||
}
|
||||
});
|
||||
|
||||
// Make sure the order is correct
|
||||
box.attribute.workspaces.forEach(
|
||||
(workspace: AgsRevealer, i: number) => {
|
||||
(workspace?.get_parent() as AgsBox)
|
||||
?.reorder_child(workspace, i);
|
||||
},
|
||||
);
|
||||
box.show_all();
|
||||
};
|
|
@ -7,7 +7,6 @@ import Corners from './ts/corners/main.ts';
|
|||
import { NotifPopups, NotifCenter } from './ts/notifications/wim.ts';
|
||||
import OSD from './ts/osd/main.ts';
|
||||
import OSK from './ts/on-screen-keyboard/main.ts';
|
||||
import Overview from './ts/overview/main.ts';
|
||||
import Powermenu from './ts/powermenu.ts';
|
||||
import QSettings from './ts/quick-settings/main.ts';
|
||||
|
||||
|
@ -23,7 +22,6 @@ export default {
|
|||
'notification-center': closeWinDelay,
|
||||
'osd': 300,
|
||||
'osk': closeWinDelay,
|
||||
'overview': closeWinDelay,
|
||||
'powermenu': closeWinDelay,
|
||||
'quick-settings': closeWinDelay,
|
||||
},
|
||||
|
@ -35,7 +33,6 @@ export default {
|
|||
NotifCenter(),
|
||||
OSD(),
|
||||
OSK(),
|
||||
Overview(),
|
||||
Powermenu(),
|
||||
QSettings(),
|
||||
|
||||
|
|
28
modules/dconf.nix
Normal file
28
modules/dconf.nix
Normal file
|
@ -0,0 +1,28 @@
|
|||
{config, ...}: let
|
||||
inherit (config.vars) mainUser;
|
||||
in {
|
||||
programs = {
|
||||
dconf.enable = true;
|
||||
};
|
||||
|
||||
home-manager.users.${mainUser} = {
|
||||
dconf.settings = {
|
||||
"org/virt-manager/virt-manager/connections" = {
|
||||
autoconnect = ["qemu:///system"];
|
||||
uris = ["qemu:///system"];
|
||||
};
|
||||
|
||||
"apps/seahorse/listing" = {
|
||||
keyrings-selected = ["gnupg://"];
|
||||
};
|
||||
|
||||
"org/gtk/settings/file-chooser" = {
|
||||
show-hidden = true;
|
||||
};
|
||||
|
||||
"org/gnome/desktop/interface" = {
|
||||
color-scheme = "prefer-dark";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
{
|
||||
config,
|
||||
hyprland,
|
||||
hyprgrass,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
|
@ -10,23 +9,16 @@
|
|||
inherit (config.vars) configDir mainUser mainMonitor;
|
||||
|
||||
isNvidia = config.hardware.nvidia.modesetting.enable;
|
||||
isTouchscreen = config.hardware.sensor.iio.enable;
|
||||
in {
|
||||
# SYSTEM CONFIG
|
||||
imports = [
|
||||
../greetd
|
||||
../dolphin.nix
|
||||
../dconf.nix
|
||||
|
||||
./packages.nix
|
||||
./security.nix
|
||||
];
|
||||
|
||||
security.pam.services.swaylock = {};
|
||||
|
||||
programs = {
|
||||
kdeconnect.enable = true;
|
||||
dconf.enable = true;
|
||||
};
|
||||
|
||||
services = {
|
||||
gnome.gnome-keyring.enable = true;
|
||||
dbus.enable = true;
|
||||
gvfs.enable = true;
|
||||
};
|
||||
|
@ -42,25 +34,16 @@ in {
|
|||
# HOME-MANAGER CONFIG
|
||||
home-manager.users.${mainUser} = {
|
||||
imports = [
|
||||
../../home/foot.nix
|
||||
../../home/dconf.nix
|
||||
../../home/mpv
|
||||
../../home/obs.nix
|
||||
../../home/swaylock.nix
|
||||
../../home/theme.nix
|
||||
../../home/wofi
|
||||
|
||||
./hycov.nix
|
||||
./hyprgrass.nix
|
||||
];
|
||||
|
||||
wayland.windowManager.hyprland = {
|
||||
enable = true;
|
||||
package = hyprland.packages.${pkgs.system}.default;
|
||||
|
||||
plugins =
|
||||
[]
|
||||
++ (optionals isTouchscreen [
|
||||
hyprgrass.packages.${pkgs.system}.default
|
||||
]);
|
||||
|
||||
settings = {
|
||||
env = let
|
||||
gset = pkgs.gsettings-desktop-schemas;
|
||||
|
@ -121,31 +104,15 @@ in {
|
|||
exec-once =
|
||||
[
|
||||
"hyprctl setcursor Dracula-cursors 24"
|
||||
"${pkgs.plasma5Packages.polkit-kde-agent}/libexec/polkit-kde-authentication-agent-1"
|
||||
"swww init --no-cache && swww img -t none ${pkgs.dracula-theme}/wallpapers/waves.png"
|
||||
"wl-paste --watch cliphist store"
|
||||
"${config.programs.kdeconnect.package}/libexec/kdeconnectd"
|
||||
"kdeconnect-indicator"
|
||||
"gnome-keyring-daemon --start --components=secrets"
|
||||
]
|
||||
++ optionals (! isNull mainMonitor)
|
||||
["hyprctl dispatch focusmonitor ${mainMonitor}"];
|
||||
|
||||
windowrule = [
|
||||
"noborder,^(wofi)$"
|
||||
|
||||
# Polkit
|
||||
"float,^(org.kde.polkit-kde-authentication-agent-1)$"
|
||||
"size 741 288,^(org.kde.polkit-kde-authentication-agent-1)$"
|
||||
"center,^(org.kde.polkit-kde-authentication-agent-1)$"
|
||||
];
|
||||
|
||||
"$mainMod" = "SUPER";
|
||||
|
||||
bind = [
|
||||
# Defaults
|
||||
"$mainMod, L, exec, lock"
|
||||
"$mainMod, Q, exec, foot"
|
||||
"$mainMod, F, fullscreen"
|
||||
"$mainMod, C, killactive, "
|
||||
"$mainMod SHIFT, SPACE, togglefloating, "
|
||||
|
@ -181,12 +148,6 @@ in {
|
|||
"$mainMod SHIFT, 9, movetoworkspace, 9"
|
||||
"$mainMod SHIFT, 0, movetoworkspace, 10"
|
||||
|
||||
# Clipboard History
|
||||
"$mainMod, V, exec, killall -r wofi || cliphist list | wofi --dmenu | cliphist decode | wl-copy"
|
||||
|
||||
",Print, exec, grim -g \"$(slurp)\" - | swappy -f -"
|
||||
"$mainMod SHIFT, C, exec, wl-color-picker"
|
||||
|
||||
",XF86AudioMute, exec, pactl set-sink-mute @DEFAULT_SINK@ toggle & ags -r 'showSpeaker()' &"
|
||||
",XF86AudioMicMute, exec, pactl set-source-mute @DEFAULT_SOURCE@ toggle"
|
||||
];
|
||||
|
@ -217,52 +178,17 @@ in {
|
|||
};
|
||||
};
|
||||
|
||||
# libs
|
||||
home.packages = with pkgs; [
|
||||
# School
|
||||
xournalpp
|
||||
virt-manager
|
||||
jetbrains.idea-ultimate
|
||||
libreoffice-fresh # TODO: declarative conf?
|
||||
hunspell
|
||||
hunspellDicts.en_CA
|
||||
config.customPkgs.rars-flatlaf
|
||||
|
||||
# Apps
|
||||
thunderbird # TODO: use programs.thunderbird
|
||||
spotifywm
|
||||
photoqt
|
||||
nextcloud-client
|
||||
jellyfin-media-player
|
||||
prismlauncher-qt5
|
||||
|
||||
/*
|
||||
Discord themes for Vencord
|
||||
https://markchan0225.github.io/RoundedDiscord/RoundedDiscord.theme.css
|
||||
https://raw.githubusercontent.com/dracula/BetterDiscord/master/Dracula_Official.theme.css
|
||||
*/
|
||||
(pkgs.discord.override {
|
||||
withOpenASAR = true;
|
||||
withVencord = true;
|
||||
})
|
||||
|
||||
# tools
|
||||
wl-color-picker
|
||||
wl-clipboard
|
||||
cliphist
|
||||
grim
|
||||
slurp
|
||||
swappy
|
||||
swayidle
|
||||
bluez-tools
|
||||
brightnessctl
|
||||
pulseaudio
|
||||
alsa-utils
|
||||
gnome.seahorse
|
||||
p7zip # for reshade
|
||||
|
||||
swww
|
||||
|
||||
## libs
|
||||
qt5.qtwayland
|
||||
qt6.qtwayland
|
||||
libayatana-appindicator
|
||||
|
|
29
modules/hyprland/hycov.nix
Normal file
29
modules/hyprland/hycov.nix
Normal file
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
hycov,
|
||||
pkgs,
|
||||
...
|
||||
}: {
|
||||
wayland.windowManager.hyprland = {
|
||||
plugins = [hycov.packages.${pkgs.system}.hycov];
|
||||
|
||||
settings = {
|
||||
plugin = {
|
||||
hycov = {
|
||||
enable_alt_release_exit = 1;
|
||||
overview_gappo = 60; #gaps width from screen
|
||||
overview_gappi = 24; #gaps width from clients
|
||||
hotarea_size = 10; #hotarea size in bottom left,10x10
|
||||
enable_hotarea = 1; # enable mouse cursor hotarea
|
||||
};
|
||||
};
|
||||
|
||||
bind = [
|
||||
"ALT, tab, hycov:toggleoverview"
|
||||
"ALT, left, hycov:movefocus, l"
|
||||
"ALT, right, hycov:movefocus, r"
|
||||
"ALT, up, hycov:movefocus, u"
|
||||
"ALT, down, hycov:movefocus, d"
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
41
modules/hyprland/hyprgrass.nix
Normal file
41
modules/hyprland/hyprgrass.nix
Normal file
|
@ -0,0 +1,41 @@
|
|||
{
|
||||
osConfig,
|
||||
hyprgrass,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) optionalAttrs;
|
||||
|
||||
isTouchscreen = osConfig.hardware.sensor.iio.enable;
|
||||
in
|
||||
optionalAttrs isTouchscreen {
|
||||
wayland.windowManager.hyprland = {
|
||||
plugins = [hyprgrass.packages.${pkgs.system}.default];
|
||||
|
||||
settings = {
|
||||
plugin = {
|
||||
touch_gestures = {
|
||||
# The default sensitivity is probably too low on tablet screens,
|
||||
# I recommend turning it up to 4.0
|
||||
sensitivity = 4.0;
|
||||
|
||||
# must be >= 3
|
||||
workspace_swipe_fingers = 3;
|
||||
|
||||
experimental = {
|
||||
# send proper cancel events to windows instead of hacky touch_up events,
|
||||
# NOT recommended as it crashed a few times, once it's stabilized I'll make it the default
|
||||
send_cancel = 0;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
gestures = {
|
||||
workspace_swipe = true;
|
||||
workspace_swipe_fingers = 3;
|
||||
workspace_swipe_cancel_ratio = 0.15;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
83
modules/hyprland/packages.nix
Normal file
83
modules/hyprland/packages.nix
Normal file
|
@ -0,0 +1,83 @@
|
|||
{
|
||||
config,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
inherit (config.vars) mainUser;
|
||||
in {
|
||||
imports = [../dolphin.nix];
|
||||
|
||||
programs = {
|
||||
kdeconnect.enable = true;
|
||||
};
|
||||
|
||||
home-manager.users.${mainUser} = {
|
||||
imports = [
|
||||
../../home/foot.nix
|
||||
../../home/mpv
|
||||
../../home/obs.nix
|
||||
../../home/wofi
|
||||
];
|
||||
|
||||
home.packages = with pkgs; [
|
||||
# School
|
||||
xournalpp
|
||||
virt-manager
|
||||
libreoffice-fresh # TODO: declarative conf?
|
||||
hunspell
|
||||
hunspellDicts.en_CA
|
||||
config.customPkgs.rars-flatlaf
|
||||
|
||||
# Apps
|
||||
thunderbird # TODO: use programs.thunderbird
|
||||
spotifywm
|
||||
photoqt
|
||||
nextcloud-client
|
||||
jellyfin-media-player
|
||||
prismlauncher-qt5
|
||||
|
||||
/*
|
||||
Discord themes for Vencord
|
||||
https://markchan0225.github.io/RoundedDiscord/RoundedDiscord.theme.css
|
||||
https://raw.githubusercontent.com/dracula/BetterDiscord/master/Dracula_Official.theme.css
|
||||
*/
|
||||
(pkgs.discord.override {
|
||||
withOpenASAR = true;
|
||||
withVencord = true;
|
||||
})
|
||||
|
||||
# tools
|
||||
wl-color-picker
|
||||
wl-clipboard
|
||||
cliphist
|
||||
grim
|
||||
slurp
|
||||
swappy
|
||||
];
|
||||
|
||||
wayland.windowManager.hyprland = {
|
||||
settings = {
|
||||
exec-once = [
|
||||
"${config.programs.kdeconnect.package}/libexec/kdeconnectd"
|
||||
"kdeconnect-indicator"
|
||||
|
||||
"wl-paste --watch cliphist store"
|
||||
];
|
||||
|
||||
windowrule = [
|
||||
"noborder,^(wofi)$"
|
||||
];
|
||||
|
||||
bind = [
|
||||
"$mainMod, Q, exec, foot"
|
||||
|
||||
# Clipboard History
|
||||
"$mainMod, V, exec, killall -r wofi || cliphist list | wofi --dmenu | cliphist decode | wl-copy"
|
||||
|
||||
",Print, exec, grim -g \"$(slurp)\" - | swappy -f -"
|
||||
"$mainMod SHIFT, C, exec, wl-color-picker"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
52
modules/hyprland/security.nix
Normal file
52
modules/hyprland/security.nix
Normal file
|
@ -0,0 +1,52 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) optionals;
|
||||
inherit (config.vars) mainUser;
|
||||
|
||||
isLaptop = config.services.logind.lidSwitch == "lock";
|
||||
in {
|
||||
imports = [
|
||||
../greetd
|
||||
];
|
||||
|
||||
security.pam.services.swaylock = {};
|
||||
services.gnome.gnome-keyring.enable = true;
|
||||
|
||||
home-manager.users.${mainUser} = {
|
||||
imports = [
|
||||
../../home/swaylock.nix
|
||||
];
|
||||
|
||||
home.packages = with pkgs; ([
|
||||
gnome.seahorse
|
||||
]
|
||||
++ optionals isLaptop [
|
||||
swayidle
|
||||
]);
|
||||
|
||||
wayland.windowManager.hyprland = {
|
||||
settings = {
|
||||
exec-once =
|
||||
[
|
||||
"gnome-keyring-daemon --start --components=secrets"
|
||||
"${pkgs.plasma5Packages.polkit-kde-agent}/libexec/polkit-kde-authentication-agent-1"
|
||||
]
|
||||
++ optionals isLaptop ["swayidle -w lock lock"];
|
||||
|
||||
windowrule = [
|
||||
"float,^(org.kde.polkit-kde-authentication-agent-1)$"
|
||||
"size 741 288,^(org.kde.polkit-kde-authentication-agent-1)$"
|
||||
"center,^(org.kde.polkit-kde-authentication-agent-1)$"
|
||||
];
|
||||
|
||||
bind = [
|
||||
"$mainMod, L, exec, lock"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
Loading…
Reference in a new issue