feat(hypr): replace ags overview with hycov
All checks were successful
Discord / discord commits (push) Has been skipped

This commit is contained in:
matt1432 2024-02-05 06:25:43 -05:00
parent 6a880378fe
commit 540db27873
20 changed files with 242 additions and 924 deletions

View file

@ -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

Binary file not shown.

BIN
flake.nix

Binary file not shown.

View file

@ -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";
};
};
}

View file

@ -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;

View file

@ -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;
}
}
}
}
}

View file

@ -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";

View file

@ -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);
};

View file

@ -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;
`);
};

View file

@ -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);
});
},
});

View file

@ -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;
};

View file

@ -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,
};

View file

@ -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();
};

View file

@ -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
View 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";
};
};
};
}

View file

@ -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

View 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"
];
};
};
}

View 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;
};
};
};
}

View 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"
];
};
};
};
}

View 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"
];
};
};
};
}