refactor(ags): start update types and use classes for cbox and popup
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
49f3a92ce3
commit
9c64b00243
30 changed files with 914 additions and 610 deletions
|
@ -2,7 +2,7 @@
|
||||||
"env": {
|
"env": {
|
||||||
"es2021": true
|
"es2021": true
|
||||||
},
|
},
|
||||||
"extends": "eslint:recommended",
|
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
|
||||||
"parser": "@typescript-eslint/parser",
|
"parser": "@typescript-eslint/parser",
|
||||||
"overrides": [],
|
"overrides": [],
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
|
@ -19,9 +19,6 @@
|
||||||
"no-unreachable-loop": ["error", { "ignore": [
|
"no-unreachable-loop": ["error", { "ignore": [
|
||||||
"ForInStatement", "ForOfStatement"
|
"ForInStatement", "ForOfStatement"
|
||||||
]}],
|
]}],
|
||||||
"no-use-before-define": ["error", {
|
|
||||||
"functions": false
|
|
||||||
}],
|
|
||||||
|
|
||||||
|
|
||||||
"block-scoped-var": ["error"],
|
"block-scoped-var": ["error"],
|
||||||
|
@ -79,6 +76,7 @@
|
||||||
|
|
||||||
"no-unused-vars": "off",
|
"no-unused-vars": "off",
|
||||||
"@typescript-eslint/no-unused-vars": "warn",
|
"@typescript-eslint/no-unused-vars": "warn",
|
||||||
|
"@typescript-eslint/no-unsafe-declaration-merging": "off",
|
||||||
|
|
||||||
"@stylistic/array-bracket-newline": ["warn", "consistent"],
|
"@stylistic/array-bracket-newline": ["warn", "consistent"],
|
||||||
"@stylistic/array-bracket-spacing": ["warn", "never"],
|
"@stylistic/array-bracket-spacing": ["warn", "never"],
|
||||||
|
|
129
modules/ags/config/global-types.d.ts
vendored
Normal file
129
modules/ags/config/global-types.d.ts
vendored
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
import { Widget } from 'types/@girs/gtk-3.0/gtk-3.0.cjs';
|
||||||
|
|
||||||
|
import { Widget as agsWidget } from 'types/widgets/widget';
|
||||||
|
export type AgsWidget = agsWidget<unknown> & Widget;
|
||||||
|
|
||||||
|
// For ./ts/applauncher/main.ts
|
||||||
|
import { Application } from 'types/service/applications.ts';
|
||||||
|
import { CursorBoxProps } from 'ts/misc/cursorbox';
|
||||||
|
export type AgsAppItem = AgsEventBox<Widget, { app: Application }
|
||||||
|
& CursorBoxProps<Widget, unknown>>;
|
||||||
|
|
||||||
|
// For ./ts/bar/hovers/keyboard.ts
|
||||||
|
export type Keyboard = {
|
||||||
|
address: string;
|
||||||
|
name: string;
|
||||||
|
rules: string;
|
||||||
|
model: string;
|
||||||
|
layout: string;
|
||||||
|
variant: string;
|
||||||
|
options: string;
|
||||||
|
active_keymap: string;
|
||||||
|
main: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
// For ./ts/bar/items/workspaces.ts
|
||||||
|
// TODO: improve type
|
||||||
|
export type Workspace = AgsRevealer<unknown & Widget, unknown & { id: number }>;
|
||||||
|
|
||||||
|
// For ./ts/bar/fullscreen.ts
|
||||||
|
export type DefaultProps = RevealerProps<CenterBoxGeneric>;
|
||||||
|
|
||||||
|
// For ./ts/media-player/gesture.ts
|
||||||
|
export type Gesture = {
|
||||||
|
attribute?: object
|
||||||
|
setup?(self: OverlayGeneric): void
|
||||||
|
props?: OverlayProps<unknown & Widget, unknown>
|
||||||
|
};
|
||||||
|
|
||||||
|
// For ./ts/media-player/mpris.ts
|
||||||
|
type PlayerDragProps = unknown & { dragging: boolean };
|
||||||
|
export type PlayerDrag = AgsCenterBox<
|
||||||
|
unknown & Widget, unknown & Widget, unknown & Widget, unknown & PlayerDragProps
|
||||||
|
>;
|
||||||
|
type Colors = {
|
||||||
|
imageAccent: string;
|
||||||
|
buttonAccent: string;
|
||||||
|
buttonText: string;
|
||||||
|
hoverAccent: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
// For ./ts/media-player
|
||||||
|
export type PlayerBoxProps = {
|
||||||
|
bgStyle: string,
|
||||||
|
player: MprisPlayer,
|
||||||
|
};
|
||||||
|
export type PlayerBox = AgsCenterBox<
|
||||||
|
unknown & Widget, unknown & Widget, unknown & Widget, PlayerBoxProps
|
||||||
|
>;
|
||||||
|
export type PlayerOverlay = AgsOverlay<AgsWidget, {
|
||||||
|
players: Map;
|
||||||
|
setup: boolean;
|
||||||
|
dragging: boolean;
|
||||||
|
includesWidget(playerW: PlayerBox): PlayerBox;
|
||||||
|
showTopOnly(): void;
|
||||||
|
moveToTop(player: PlayerBox): void;
|
||||||
|
}>;
|
||||||
|
export type PlayerButtonType = {
|
||||||
|
player: MprisPlayer
|
||||||
|
colors: Var<Colors>
|
||||||
|
items: Array<[name: string, widget: AgsWidget]>
|
||||||
|
onClick: string
|
||||||
|
prop: string
|
||||||
|
};
|
||||||
|
|
||||||
|
// For CursorBox
|
||||||
|
import { CursorBox, CursorBoxProps } from 'ts/misc/cursorbox';
|
||||||
|
export type CursorBox = CursorBox;
|
||||||
|
export type CursorBoxProps = CursorBoxProps;
|
||||||
|
|
||||||
|
// For PopupWindow
|
||||||
|
export type PopupChild = Binding<
|
||||||
|
Var<Widget>,
|
||||||
|
'is_listening' | 'is_polling' | 'value',
|
||||||
|
Widget[]
|
||||||
|
>;
|
||||||
|
export type CloseType = 'none' | 'stay' | 'released' | 'clicked';
|
||||||
|
export type PopupWindowProps<Child extends Widget, Attr = unknown> =
|
||||||
|
WindowProps<Child> & {
|
||||||
|
transition?: RevealerProps<Widget>['transition']
|
||||||
|
transition_duration?: number
|
||||||
|
bezier?: string
|
||||||
|
on_open?(self: AgsWindow<Widget, unknown>): void
|
||||||
|
on_close?(self: AgsWindow<Widget, unknown>): void
|
||||||
|
blur?: boolean
|
||||||
|
close_on_unfocus?: CloseType
|
||||||
|
attribute?: Attr;
|
||||||
|
content?: Widget
|
||||||
|
anchor?: Array<'top' | 'bottom' | 'right' | 'left'>;
|
||||||
|
};
|
||||||
|
import { PopupWindow } from 'ts/misc/popup';
|
||||||
|
export type PopupWindow = PopupWindow;
|
||||||
|
|
||||||
|
|
||||||
|
// Generic widgets
|
||||||
|
import AgsBox from 'types/widgets/box.ts';
|
||||||
|
export type BoxGeneric = AgsBox<unknown & Widget, unknown>;
|
||||||
|
|
||||||
|
import AgsCenterBox, { CenterBoxProps } from 'types/widgets/centerbox';
|
||||||
|
export type CenterBoxGeneric = AgsCenterBox<
|
||||||
|
unknown & Widget, unknown & Widget, unknown & Widget, unknown
|
||||||
|
>;
|
||||||
|
export type CenterBoxPropsGeneric = CenterBoxProps<
|
||||||
|
unknown & Widget, unknown & Widget, unknown & Widget, unknown
|
||||||
|
>;
|
||||||
|
|
||||||
|
import AgsEventBox from 'types/widgets/eventbox.ts';
|
||||||
|
export type EventBoxGeneric = AgsEventBox<unknown & Widget, unknown>;
|
||||||
|
|
||||||
|
import AgsLabel from 'types/widgets/label.ts';
|
||||||
|
export type LabelGeneric = AgsLabel<unknown>;
|
||||||
|
|
||||||
|
import AgsOverlay, { OverlayProps } from 'types/widgets/overlay.ts';
|
||||||
|
export type OverlayGeneric = AgsOverlay<unknown & Widget, unknown>;
|
||||||
|
|
||||||
|
import AgsRevealer, { RevealerProps } from 'types/widgets/revealer.ts';
|
||||||
|
export type RevealerGeneric = AgsRevealer<unknown & Widget, unknown>;
|
||||||
|
|
||||||
|
import AgsStack from 'types/widgets/stack.ts';
|
||||||
|
export type StackGeneric = AgsStack<unknown & Widget, unknown>;
|
|
@ -27,7 +27,7 @@
|
||||||
padding: 4.5px 9px;
|
padding: 4.5px 9px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.hover box {
|
&:hover box {
|
||||||
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;
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
padding: 4.5px 9px;
|
padding: 4.5px 9px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.hover box {
|
&:hover box {
|
||||||
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;
|
||||||
|
|
|
@ -48,7 +48,7 @@
|
||||||
border 0.5s ease-in-out;
|
border 0.5s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toggle-on.hover, .toggle-off.hover {
|
.toggle-on:hover, .toggle-off:hover {
|
||||||
background-color: rgba(127, 132, 156, 0.4);
|
background-color: rgba(127, 132, 156, 0.4);
|
||||||
transition: background-color 0.5s ease-in-out,
|
transition: background-color 0.5s ease-in-out,
|
||||||
border 0.5s ease-in-out;
|
border 0.5s ease-in-out;
|
||||||
|
|
|
@ -15,7 +15,7 @@ const ON_CLICK_TRIGGERS = [
|
||||||
];
|
];
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import AgsWindow from 'types/widgets/window';
|
import { PopupWindow } from 'global-types';
|
||||||
import { Subprocess } from 'types/@girs/gio-2.0/gio-2.0.cjs';
|
import { Subprocess } from 'types/@girs/gio-2.0/gio-2.0.cjs';
|
||||||
type Layer = {
|
type Layer = {
|
||||||
address: string;
|
address: string;
|
||||||
|
@ -54,7 +54,7 @@ class Pointers extends Service {
|
||||||
|
|
||||||
#process = null as Subprocess | null;
|
#process = null as Subprocess | null;
|
||||||
#lastLine = '';
|
#lastLine = '';
|
||||||
#pointers = [] as Array<String>;
|
#pointers = [] as Array<string>;
|
||||||
|
|
||||||
get process() {
|
get process() {
|
||||||
return this.#process;
|
return this.#process;
|
||||||
|
@ -114,11 +114,11 @@ class Pointers extends Service {
|
||||||
#initAppConnection() {
|
#initAppConnection() {
|
||||||
App.connect('window-toggled', () => {
|
App.connect('window-toggled', () => {
|
||||||
const anyVisibleAndClosable =
|
const anyVisibleAndClosable =
|
||||||
(Array.from(App.windows) as Array<[string, AgsWindow]>)
|
(Array.from(App.windows) as Array<[string, PopupWindow]>)
|
||||||
.some((w) => {
|
.some((w) => {
|
||||||
const closable = w[1].attribute?.close_on_unfocus &&
|
const closable = w[1].close_on_unfocus &&
|
||||||
!(w[1].attribute.close_on_unfocus === 'none' ||
|
!(w[1].close_on_unfocus === 'none' ||
|
||||||
w[1].attribute.close_on_unfocus === 'stay');
|
w[1].close_on_unfocus === 'stay');
|
||||||
|
|
||||||
return w[1].visible && closable;
|
return w[1].visible && closable;
|
||||||
});
|
});
|
||||||
|
@ -134,10 +134,10 @@ class Pointers extends Service {
|
||||||
}
|
}
|
||||||
|
|
||||||
static detectClickedOutside(clickStage: string) {
|
static detectClickedOutside(clickStage: string) {
|
||||||
const toClose = (Array.from(App.windows) as Array<[string, AgsWindow]>)
|
const toClose = (Array.from(App.windows) as Array<[string, PopupWindow]>)
|
||||||
.some((w) => {
|
.some((w) => {
|
||||||
const closable = (w[1].attribute?.close_on_unfocus &&
|
const closable = (w[1].close_on_unfocus &&
|
||||||
w[1].attribute.close_on_unfocus === clickStage);
|
w[1].close_on_unfocus === clickStage);
|
||||||
|
|
||||||
return w[1].visible && closable;
|
return w[1].visible && closable;
|
||||||
});
|
});
|
||||||
|
@ -190,11 +190,11 @@ class Pointers extends Service {
|
||||||
|
|
||||||
const widgets = overlayLayer.filter((n) => {
|
const widgets = overlayLayer.filter((n) => {
|
||||||
const window =
|
const window =
|
||||||
(App.getWindow(n.namespace) as AgsWindow);
|
(App.getWindow(n.namespace) as PopupWindow);
|
||||||
|
|
||||||
return window &&
|
return window &&
|
||||||
window.attribute?.close_on_unfocus &&
|
window.close_on_unfocus &&
|
||||||
window.attribute?.close_on_unfocus ===
|
window.close_on_unfocus ===
|
||||||
clickStage;
|
clickStage;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import App from 'resource:///com/github/Aylur/ags/app.js';
|
import App from 'resource:///com/github/Aylur/ags/app.js';
|
||||||
import Applications from 'resource:///com/github/Aylur/ags/service/applications.js';
|
import Applications from 'resource:///com/github/Aylur/ags/service/applications.js';
|
||||||
// FIXME: find cleaner way to import this
|
// @ts-expect-error find cleaner way to import this
|
||||||
// @ts-expect-error
|
import { Fzf, FzfResultItem } from 'file:///home/matt/.nix/modules/ags/config/node_modules/fzf/dist/fzf.es.js';
|
||||||
import { Fzf } from 'file:///home/matt/.nix/modules/ags/config/node_modules/fzf/dist/fzf.es.js';
|
|
||||||
|
|
||||||
import { Box, Entry, Icon, Label, ListBox, Revealer, Scrollable } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Box, Entry, Icon, Label, ListBox, Revealer, Scrollable } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
|
|
||||||
|
@ -10,14 +9,13 @@ import PopupWindow from '../misc/popup.ts';
|
||||||
import AppItem from './app-item.ts';
|
import AppItem from './app-item.ts';
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import { Application } from 'types/service/applications.ts';
|
|
||||||
import { ListBoxRow } from 'types/@girs/gtk-3.0/gtk-3.0.cjs';
|
import { ListBoxRow } from 'types/@girs/gtk-3.0/gtk-3.0.cjs';
|
||||||
import AgsEventBox from 'types/widgets/eventbox';
|
import { Application } from 'types/service/applications.ts';
|
||||||
|
import { AgsAppItem } from 'global-types';
|
||||||
|
|
||||||
|
|
||||||
const Applauncher = (window_name = 'applauncher') => {
|
const Applauncher = (window_name = 'applauncher') => {
|
||||||
let fzfResults: Array<any>;
|
let fzfResults: FzfResultItem<Application>[];
|
||||||
// @ts-expect-error
|
|
||||||
const list = ListBox();
|
const list = ListBox();
|
||||||
|
|
||||||
const setSort = (text: string) => {
|
const setSort = (text: string) => {
|
||||||
|
@ -31,12 +29,9 @@ const Applauncher = (window_name = 'applauncher') => {
|
||||||
});
|
});
|
||||||
|
|
||||||
fzfResults = fzf.find(text);
|
fzfResults = fzf.find(text);
|
||||||
list.set_sort_func(
|
list.set_sort_func((a, b) => {
|
||||||
(a: ListBoxRow, b: ListBoxRow) => {
|
const row1 = (a.get_children()[0] as AgsAppItem).attribute.app.name;
|
||||||
const row1 = (a.get_children()[0] as AgsEventBox)
|
const row2 = (b.get_children()[0] as AgsAppItem).attribute.app.name;
|
||||||
?.attribute.app.name;
|
|
||||||
const row2 = (b.get_children()[0] as AgsEventBox)
|
|
||||||
?.attribute.app.name;
|
|
||||||
|
|
||||||
if (!row1 || !row2) {
|
if (!row1 || !row2) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -44,12 +39,11 @@ const Applauncher = (window_name = 'applauncher') => {
|
||||||
|
|
||||||
return fzfResults.indexOf(row1) -
|
return fzfResults.indexOf(row1) -
|
||||||
fzfResults.indexOf(row1) || 0;
|
fzfResults.indexOf(row1) || 0;
|
||||||
},
|
});
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const makeNewChildren = () => {
|
const makeNewChildren = () => {
|
||||||
const rows = list.get_children() as Array<ListBoxRow>;
|
const rows = list.get_children() as ListBoxRow[];
|
||||||
|
|
||||||
rows.forEach((ch) => {
|
rows.forEach((ch) => {
|
||||||
ch.destroy();
|
ch.destroy();
|
||||||
|
@ -94,14 +88,14 @@ const Applauncher = (window_name = 'applauncher') => {
|
||||||
setSort(text);
|
setSort(text);
|
||||||
let visibleApps = 0;
|
let visibleApps = 0;
|
||||||
|
|
||||||
const rows = list.get_children() as Array<ListBoxRow>;
|
const rows = list.get_children() as ListBoxRow[];
|
||||||
|
|
||||||
rows.forEach((row) => {
|
rows.forEach((row) => {
|
||||||
row.changed();
|
row.changed();
|
||||||
|
|
||||||
const item = (row.get_children()[0] as AgsEventBox);
|
const item = (row.get_children()[0] as AgsAppItem);
|
||||||
|
|
||||||
if (item?.attribute.app) {
|
if (item.attribute.app) {
|
||||||
const isMatching = fzfResults.find((r) => {
|
const isMatching = fzfResults.find((r) => {
|
||||||
return r.item.name === item.attribute.app.name;
|
return r.item.name === item.attribute.app.name;
|
||||||
});
|
});
|
||||||
|
@ -162,5 +156,5 @@ const Applauncher = (window_name = 'applauncher') => {
|
||||||
export default () => PopupWindow({
|
export default () => PopupWindow({
|
||||||
name: 'applauncher',
|
name: 'applauncher',
|
||||||
keymode: 'on-demand',
|
keymode: 'on-demand',
|
||||||
child: Applauncher(),
|
content: Applauncher(),
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,8 +5,8 @@ import { Box, EventBox, Revealer, Window } from 'resource:///com/github/Aylur/ag
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import { Variable as Var } from 'types/variable';
|
import { Variable as Var } from 'types/variable';
|
||||||
import AgsBox from 'types/widgets/box';
|
import { BoxGeneric, DefaultProps } from 'global-types';
|
||||||
import { RevealerProps } from 'types/widgets/revealer';
|
|
||||||
|
|
||||||
const BarCloser = (variable: Var<boolean>) => Window({
|
const BarCloser = (variable: Var<boolean>) => Window({
|
||||||
name: 'bar-closer',
|
name: 'bar-closer',
|
||||||
|
@ -30,7 +30,7 @@ const BarCloser = (variable: Var<boolean>) => Window({
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default (props: RevealerProps) => {
|
export default (props?: DefaultProps) => {
|
||||||
const Revealed = Variable(true);
|
const Revealed = Variable(true);
|
||||||
const barCloser = BarCloser(Revealed);
|
const barCloser = BarCloser(Revealed);
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ export default (props: RevealerProps) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const checkGlobalFsState = (_: AgsBox, fullscreen: boolean) => {
|
const checkGlobalFsState = (_: BoxGeneric, fullscreen: boolean) => {
|
||||||
Revealed.value = !fullscreen;
|
Revealed.value = !fullscreen;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -6,22 +6,11 @@ import HoverRevealer from './hover-revealer.ts';
|
||||||
|
|
||||||
const DEFAULT_KB = 'at-translated-set-2-keyboard';
|
const DEFAULT_KB = 'at-translated-set-2-keyboard';
|
||||||
|
|
||||||
import AgsLabel from 'types/widgets/label.ts';
|
// Types
|
||||||
type Keyboard = {
|
import { Keyboard, LabelGeneric } from 'global-types';
|
||||||
address: string;
|
|
||||||
name: string;
|
|
||||||
rules: string;
|
|
||||||
model: string;
|
|
||||||
layout: string;
|
|
||||||
variant: string;
|
|
||||||
options: string;
|
|
||||||
active_keymap: string;
|
|
||||||
main: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
const getKbdLayout = (self: LabelGeneric, _: string, layout: string) => {
|
||||||
const getKbdLayout = (self: AgsLabel, _: string, layout: string) => {
|
|
||||||
if (layout) {
|
if (layout) {
|
||||||
if (layout === 'error') {
|
if (layout === 'error') {
|
||||||
return;
|
return;
|
||||||
|
@ -35,7 +24,7 @@ const getKbdLayout = (self: AgsLabel, _: string, layout: string) => {
|
||||||
// At launch, kb layout is undefined
|
// At launch, kb layout is undefined
|
||||||
Hyprland.sendMessage('j/devices').then((obj) => {
|
Hyprland.sendMessage('j/devices').then((obj) => {
|
||||||
const keyboards = Array.from(JSON.parse(obj)
|
const keyboards = Array.from(JSON.parse(obj)
|
||||||
.keyboards) as Array<Keyboard>;
|
.keyboards) as Keyboard[];
|
||||||
const kb = keyboards.find((v) => v.name === DEFAULT_KB);
|
const kb = keyboards.find((v) => v.name === DEFAULT_KB);
|
||||||
|
|
||||||
if (kb) {
|
if (kb) {
|
||||||
|
|
|
@ -9,15 +9,15 @@ import Separator from '../../misc/separator.ts';
|
||||||
const SPACING = 4;
|
const SPACING = 4;
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import AgsWindow from 'types/widgets/window.ts';
|
import { PopupWindow } from 'global-types';
|
||||||
|
|
||||||
|
|
||||||
export default () => CursorBox({
|
export default () => CursorBox({
|
||||||
class_name: 'toggle-off',
|
class_name: 'toggle-off',
|
||||||
|
|
||||||
on_primary_click_release: (self) => {
|
on_primary_click_release: (self) => {
|
||||||
(App.getWindow('notification-center') as AgsWindow)
|
(App.getWindow('notification-center') as PopupWindow)
|
||||||
?.attribute.set_x_pos(
|
.set_x_pos(
|
||||||
self.get_allocation(),
|
self.get_allocation(),
|
||||||
'right',
|
'right',
|
||||||
);
|
);
|
||||||
|
|
|
@ -14,9 +14,7 @@ import Separator from '../../misc/separator.ts';
|
||||||
const SPACING = 4;
|
const SPACING = 4;
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import AgsRevealer from 'types/widgets/revealer.ts';
|
import { PopupWindow } from 'global-types';
|
||||||
import AgsBox from 'types/widgets/box.ts';
|
|
||||||
import AgsWindow from 'types/widgets/window.ts';
|
|
||||||
|
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
|
@ -36,8 +34,8 @@ export default () => {
|
||||||
class_name: 'toggle-off',
|
class_name: 'toggle-off',
|
||||||
|
|
||||||
on_primary_click_release: (self) => {
|
on_primary_click_release: (self) => {
|
||||||
(App.getWindow('quick-settings') as AgsWindow)
|
(App.getWindow('quick-settings') as PopupWindow)
|
||||||
?.attribute.set_x_pos(
|
.set_x_pos(
|
||||||
self.get_allocation(),
|
self.get_allocation(),
|
||||||
'right',
|
'right',
|
||||||
);
|
);
|
||||||
|
@ -55,17 +53,15 @@ export default () => {
|
||||||
|
|
||||||
attribute: {
|
attribute: {
|
||||||
hoverRevealers: hoverRevealers.map((rev) => {
|
hoverRevealers: hoverRevealers.map((rev) => {
|
||||||
const box = rev.child as AgsBox;
|
const box = rev.child;
|
||||||
|
|
||||||
return box.children[1];
|
return box.children[1];
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
on_hover_lost: (self) => {
|
on_hover_lost: (self) => {
|
||||||
self.attribute.hoverRevealers.forEach(
|
self.attribute.hoverRevealers.forEach((rev) => {
|
||||||
(rev: AgsRevealer) => {
|
|
||||||
rev.reveal_child = false;
|
rev.reveal_child = false;
|
||||||
},
|
});
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
child: Box({
|
child: Box({
|
||||||
|
|
|
@ -10,7 +10,6 @@ const SPACING = 12;
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import { TrayItem } from 'types/service/systemtray.ts';
|
import { TrayItem } from 'types/service/systemtray.ts';
|
||||||
import AgsRevealer from 'types/widgets/revealer.ts';
|
|
||||||
|
|
||||||
|
|
||||||
const SysTrayItem = (item: TrayItem) => {
|
const SysTrayItem = (item: TrayItem) => {
|
||||||
|
@ -54,7 +53,7 @@ const SysTray = () => MenuBar({
|
||||||
self.child = w;
|
self.child = w;
|
||||||
self.show_all();
|
self.show_all();
|
||||||
|
|
||||||
(<AgsRevealer> w.child).reveal_child = true;
|
w.child.reveal_child = true;
|
||||||
}, 'added')
|
}, 'added')
|
||||||
|
|
||||||
.hook(SystemTray, (_, id) => {
|
.hook(SystemTray, (_, id) => {
|
||||||
|
|
|
@ -8,10 +8,13 @@ import CursorBox from '../../misc/cursorbox.ts';
|
||||||
const URGENT_DURATION = 1000;
|
const URGENT_DURATION = 1000;
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import AgsBox from 'types/widgets/box.ts';
|
import {
|
||||||
import AgsRevealer from 'types/widgets/revealer.ts';
|
BoxGeneric,
|
||||||
import AgsOverlay from 'types/widgets/overlay.ts';
|
EventBoxGeneric,
|
||||||
import AgsEventBox from 'types/widgets/eventbox.ts';
|
OverlayGeneric,
|
||||||
|
RevealerGeneric,
|
||||||
|
Workspace,
|
||||||
|
} from 'global-types';
|
||||||
|
|
||||||
|
|
||||||
const Workspace = ({ id }: { id: number }) => {
|
const Workspace = ({ id }: { id: number }) => {
|
||||||
|
@ -31,7 +34,10 @@ const Workspace = ({ id }: { id: number }) => {
|
||||||
class_name: 'button',
|
class_name: 'button',
|
||||||
|
|
||||||
setup: (self) => {
|
setup: (self) => {
|
||||||
const update = (_: AgsBox, addr: string | undefined) => {
|
const update = (
|
||||||
|
_: BoxGeneric,
|
||||||
|
addr: string | undefined,
|
||||||
|
) => {
|
||||||
const workspace = Hyprland.getWorkspace(id);
|
const workspace = Hyprland.getWorkspace(id);
|
||||||
const occupied = workspace && workspace.windows > 0;
|
const occupied = workspace && workspace.windows > 0;
|
||||||
|
|
||||||
|
@ -79,13 +85,13 @@ export default () => {
|
||||||
const L_PADDING = 16;
|
const L_PADDING = 16;
|
||||||
const WS_WIDTH = 30;
|
const WS_WIDTH = 30;
|
||||||
|
|
||||||
const updateHighlight = (self: AgsBox) => {
|
const updateHighlight = (self: BoxGeneric) => {
|
||||||
const currentId = Hyprland.active.workspace.id;
|
const currentId = Hyprland.active.workspace.id;
|
||||||
|
|
||||||
const indicators = (((self.get_parent() as AgsOverlay)
|
const indicators = (((self.get_parent() as OverlayGeneric)
|
||||||
.child as AgsEventBox)
|
.child as EventBoxGeneric)
|
||||||
.child as AgsBox)
|
.child as BoxGeneric)
|
||||||
.children as Array<AgsRevealer>;
|
.children as Workspace[];
|
||||||
|
|
||||||
const currentIndex = indicators
|
const currentIndex = indicators
|
||||||
.findIndex((w) => w.attribute.id === currentId);
|
.findIndex((w) => w.attribute.id === currentId);
|
||||||
|
@ -111,25 +117,25 @@ export default () => {
|
||||||
child: Box({
|
child: Box({
|
||||||
class_name: 'workspaces',
|
class_name: 'workspaces',
|
||||||
|
|
||||||
attribute: { workspaces: [] },
|
attribute: { workspaces: [] as Workspace[] },
|
||||||
|
|
||||||
setup: (self) => {
|
setup: (self) => {
|
||||||
const workspaces = (): Array<AgsRevealer> =>
|
|
||||||
self.attribute.workspaces;
|
|
||||||
|
|
||||||
const refresh = () => {
|
const refresh = () => {
|
||||||
(self.children as Array<AgsRevealer>).forEach((rev) => {
|
(self.children as RevealerGeneric[])
|
||||||
|
.forEach((rev) => {
|
||||||
rev.reveal_child = false;
|
rev.reveal_child = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
workspaces().forEach((ws) => {
|
self.attribute.workspaces
|
||||||
|
.forEach((ws) => {
|
||||||
ws.reveal_child = true;
|
ws.reveal_child = true;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateWorkspaces = () => {
|
const updateWorkspaces = () => {
|
||||||
Hyprland.workspaces.forEach((ws) => {
|
Hyprland.workspaces.forEach((ws) => {
|
||||||
const currentWs = (self.children as Array<AgsBox>)
|
const currentWs =
|
||||||
|
(self.children as Workspace[])
|
||||||
.find((ch) => ch.attribute.id === ws.id);
|
.find((ch) => ch.attribute.id === ws.id);
|
||||||
|
|
||||||
if (!currentWs && ws.id > 0) {
|
if (!currentWs && ws.id > 0) {
|
||||||
|
@ -139,21 +145,22 @@ export default () => {
|
||||||
self.show_all();
|
self.show_all();
|
||||||
|
|
||||||
// Make sure the order is correct
|
// Make sure the order is correct
|
||||||
workspaces().forEach((workspace, i) => {
|
self.attribute.workspaces.forEach((workspace, i) => {
|
||||||
(<AgsBox> workspace.get_parent()).reorder_child(
|
(workspace.get_parent() as BoxGeneric)
|
||||||
workspace,
|
.reorder_child(workspace, i);
|
||||||
i,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
self.hook(Hyprland, () => {
|
self.hook(Hyprland, () => {
|
||||||
self.attribute.workspaces =
|
self.attribute.workspaces =
|
||||||
(self.children as Array<AgsBox>).filter((ch) => {
|
(self.children as Workspace[])
|
||||||
|
.filter((ch) => {
|
||||||
return Hyprland.workspaces.find((ws) => {
|
return Hyprland.workspaces.find((ws) => {
|
||||||
return ws.id === ch.attribute.id;
|
return ws.id === ch.attribute.id;
|
||||||
});
|
});
|
||||||
}).sort((a, b) => a.attribute.id - b.attribute.id);
|
})
|
||||||
|
.sort((a, b) =>
|
||||||
|
a.attribute.id - b.attribute.id);
|
||||||
|
|
||||||
updateWorkspaces();
|
updateWorkspaces();
|
||||||
refresh();
|
refresh();
|
||||||
|
|
|
@ -26,10 +26,7 @@ export default (
|
||||||
.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', (_, context) => {
|
widget.connect('draw', (_, cr) => {
|
||||||
// FIXME: get proper Context type
|
|
||||||
const cr = context as any;
|
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
|
|
|
@ -90,7 +90,7 @@ export default () => PopupWindow({
|
||||||
anchor: ['top'],
|
anchor: ['top'],
|
||||||
margins: [TOP_MARGIN, 0, 0, 0],
|
margins: [TOP_MARGIN, 0, 0, 0],
|
||||||
|
|
||||||
child: Box({
|
content: Box({
|
||||||
class_name: 'date',
|
class_name: 'date',
|
||||||
vertical: true,
|
vertical: true,
|
||||||
|
|
||||||
|
|
|
@ -10,20 +10,15 @@ const TRANSITION = `transition: margin ${ANIM_DURATION}ms ease,
|
||||||
opacity ${ANIM_DURATION}ms ease;`;
|
opacity ${ANIM_DURATION}ms ease;`;
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import AgsOverlay from 'types/widgets/overlay';
|
import {
|
||||||
import OverlayProps from 'types/widgets/overlay';
|
CenterBoxGeneric,
|
||||||
import AgsBox from 'types/widgets/box';
|
Gesture,
|
||||||
import AgsCenterBox from 'types/widgets/centerbox';
|
OverlayGeneric,
|
||||||
import { Connectable } from 'types/widgets/widget';
|
PlayerBox,
|
||||||
type Gesture = {
|
} from 'global-types';
|
||||||
attribute?: Object
|
|
||||||
setup?(self: Connectable<AgsOverlay> & AgsOverlay): void
|
|
||||||
props?: OverlayProps
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
export default ({
|
export default ({
|
||||||
attribute = {},
|
|
||||||
setup = () => {/**/},
|
setup = () => {/**/},
|
||||||
...props
|
...props
|
||||||
}: Gesture) => {
|
}: Gesture) => {
|
||||||
|
@ -39,10 +34,11 @@ export default ({
|
||||||
const content = Overlay({
|
const content = Overlay({
|
||||||
...props,
|
...props,
|
||||||
attribute: {
|
attribute: {
|
||||||
...attribute,
|
players: new Map(),
|
||||||
|
setup: false,
|
||||||
dragging: false,
|
dragging: false,
|
||||||
|
|
||||||
includesWidget: (playerW: AgsOverlay) => {
|
includesWidget: (playerW: OverlayGeneric) => {
|
||||||
return content.overlays.find((w) => w === playerW);
|
return content.overlays.find((w) => w === playerW);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -50,7 +46,7 @@ export default ({
|
||||||
over.visible = over === content.overlays.at(-1);
|
over.visible = over === content.overlays.at(-1);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
moveToTop: (player: AgsCenterBox) => {
|
moveToTop: (player: CenterBoxGeneric) => {
|
||||||
player.visible = true;
|
player.visible = true;
|
||||||
content.reorder_overlay(player, -1);
|
content.reorder_overlay(player, -1);
|
||||||
timeout(ANIM_DURATION, () => {
|
timeout(ANIM_DURATION, () => {
|
||||||
|
@ -82,7 +78,7 @@ export default ({
|
||||||
|
|
||||||
self.attribute.dragging = true;
|
self.attribute.dragging = true;
|
||||||
let offset = gesture.get_offset()[1];
|
let offset = gesture.get_offset()[1];
|
||||||
const playerBox = self.overlays.at(-1) as AgsBox;
|
const playerBox = self.overlays.at(-1) as PlayerBox;
|
||||||
|
|
||||||
if (!offset) {
|
if (!offset) {
|
||||||
return;
|
return;
|
||||||
|
@ -118,7 +114,7 @@ export default ({
|
||||||
self.attribute.dragging = false;
|
self.attribute.dragging = false;
|
||||||
const offset = gesture.get_offset()[1];
|
const offset = gesture.get_offset()[1];
|
||||||
|
|
||||||
const playerBox = self.overlays.at(-1) as AgsBox;
|
const playerBox = self.overlays.at(-1) as PlayerBox;
|
||||||
|
|
||||||
// If crosses threshold after letting go, slide away
|
// If crosses threshold after letting go, slide away
|
||||||
if (offset && Math.abs(offset) > MAX_OFFSET) {
|
if (offset && Math.abs(offset) > MAX_OFFSET) {
|
||||||
|
|
|
@ -31,17 +31,23 @@ const icons = {
|
||||||
// Types
|
// Types
|
||||||
import { MprisPlayer } from 'types/service/mpris.ts';
|
import { MprisPlayer } from 'types/service/mpris.ts';
|
||||||
import { Variable as Var } from 'types/variable';
|
import { Variable as Var } from 'types/variable';
|
||||||
import AgsOverlay from 'types/widgets/overlay.ts';
|
|
||||||
import AgsCenterBox, { CenterBoxProps } from 'types/widgets/centerbox.ts';
|
import {
|
||||||
import AgsLabel from 'types/widgets/label.ts';
|
AgsWidget,
|
||||||
import AgsIcon from 'types/widgets/icon.ts';
|
CenterBoxPropsGeneric,
|
||||||
import AgsStack from 'types/widgets/stack.ts';
|
Colors,
|
||||||
|
PlayerBox,
|
||||||
|
PlayerButtonType,
|
||||||
|
PlayerDrag,
|
||||||
|
PlayerOverlay,
|
||||||
|
StackGeneric,
|
||||||
|
} from 'global-types';
|
||||||
|
|
||||||
|
|
||||||
export const CoverArt = (
|
export const CoverArt = (
|
||||||
player: MprisPlayer,
|
player: MprisPlayer,
|
||||||
colors: Var<any>,
|
colors: Var<Colors>,
|
||||||
props: CenterBoxProps,
|
props: CenterBoxPropsGeneric,
|
||||||
) => CenterBox({
|
) => CenterBox({
|
||||||
...props,
|
...props,
|
||||||
vertical: true,
|
vertical: true,
|
||||||
|
@ -51,7 +57,7 @@ export const CoverArt = (
|
||||||
player,
|
player,
|
||||||
},
|
},
|
||||||
|
|
||||||
setup: (self) => {
|
setup: (self: PlayerBox) => {
|
||||||
// Give temp cover art
|
// Give temp cover art
|
||||||
readFileAsync(player.cover_path).catch(() => {
|
readFileAsync(player.cover_path).catch(() => {
|
||||||
if (!colors.value && !player.track_cover_url) {
|
if (!colors.value && !player.track_cover_url) {
|
||||||
|
@ -93,7 +99,7 @@ export const CoverArt = (
|
||||||
background-position: center;
|
background-position: center;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
if (!(self.get_parent() as AgsCenterBox)
|
if (!(self.get_parent() as PlayerDrag)
|
||||||
.attribute.dragging) {
|
.attribute.dragging) {
|
||||||
self.setCss(self.attribute.bgStyle);
|
self.setCss(self.attribute.bgStyle);
|
||||||
}
|
}
|
||||||
|
@ -126,16 +132,18 @@ export const ArtistLabel = (player: MprisPlayer) => Label({
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
export const PlayerIcon = (player: MprisPlayer, overlay: AgsOverlay) => {
|
export const PlayerIcon = (player: MprisPlayer, overlay: PlayerOverlay) => {
|
||||||
const playerIcon = (
|
const playerIcon = (
|
||||||
p: MprisPlayer,
|
p: MprisPlayer,
|
||||||
widget?: AgsOverlay,
|
widget?: PlayerOverlay,
|
||||||
over?: AgsOverlay,
|
playerBox?: PlayerBox,
|
||||||
) => CursorBox({
|
) => CursorBox({
|
||||||
tooltip_text: p.identity || '',
|
tooltip_text: p.identity || '',
|
||||||
|
|
||||||
on_primary_click_release: () => {
|
on_primary_click_release: () => {
|
||||||
widget?.attribute.moveToTop(over);
|
if (widget && playerBox) {
|
||||||
|
widget.attribute.moveToTop(playerBox);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
child: Icon({
|
child: Icon({
|
||||||
|
@ -153,7 +161,7 @@ export const PlayerIcon = (player: MprisPlayer, overlay: AgsOverlay) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
return Box().hook(Mpris, (self) => {
|
return Box().hook(Mpris, (self) => {
|
||||||
const grandPa = self.get_parent()?.get_parent();
|
const grandPa = self.get_parent()?.get_parent() as AgsWidget;
|
||||||
|
|
||||||
if (!grandPa) {
|
if (!grandPa) {
|
||||||
return;
|
return;
|
||||||
|
@ -162,13 +170,13 @@ export const PlayerIcon = (player: MprisPlayer, overlay: AgsOverlay) => {
|
||||||
const thisIndex = overlay.overlays
|
const thisIndex = overlay.overlays
|
||||||
.indexOf(grandPa);
|
.indexOf(grandPa);
|
||||||
|
|
||||||
self.children = (overlay.overlays as Array<AgsOverlay>)
|
self.children = (overlay.overlays as PlayerBox[])
|
||||||
.map((over, i) => {
|
.map((playerBox, i) => {
|
||||||
self.children.push(Separator(2));
|
self.children.push(Separator(2));
|
||||||
|
|
||||||
return i === thisIndex ?
|
return i === thisIndex ?
|
||||||
playerIcon(player) :
|
playerIcon(player) :
|
||||||
playerIcon(over.attribute.player, overlay, over);
|
playerIcon(playerBox.attribute.player, overlay, playerBox);
|
||||||
})
|
})
|
||||||
.reverse();
|
.reverse();
|
||||||
});
|
});
|
||||||
|
@ -179,7 +187,7 @@ const display = Gdk.Display.get_default();
|
||||||
|
|
||||||
export const PositionSlider = (
|
export const PositionSlider = (
|
||||||
player: MprisPlayer,
|
player: MprisPlayer,
|
||||||
colors: Var<any>,
|
colors: Var<Colors>,
|
||||||
) => Slider({
|
) => Slider({
|
||||||
class_name: 'position-slider',
|
class_name: 'position-slider',
|
||||||
vpack: 'center',
|
vpack: 'center',
|
||||||
|
@ -258,13 +266,6 @@ export const PositionSlider = (
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
type PlayerButtonType = {
|
|
||||||
player: MprisPlayer
|
|
||||||
colors: Var<any>
|
|
||||||
items: Array<[name: string, widget: AgsLabel | AgsIcon]>
|
|
||||||
onClick: string
|
|
||||||
prop: string
|
|
||||||
};
|
|
||||||
const PlayerButton = ({
|
const PlayerButton = ({
|
||||||
player,
|
player,
|
||||||
colors,
|
colors,
|
||||||
|
@ -316,7 +317,7 @@ const PlayerButton = ({
|
||||||
setup: (self) => {
|
setup: (self) => {
|
||||||
self
|
self
|
||||||
.hook(player, () => {
|
.hook(player, () => {
|
||||||
(self.child as AgsStack).shown = `${player[prop]}`;
|
(self.child as StackGeneric).shown = `${player[prop]}`;
|
||||||
})
|
})
|
||||||
.hook(colors, () => {
|
.hook(colors, () => {
|
||||||
if (!Mpris.players.find((p) => player === p)) {
|
if (!Mpris.players.find((p) => player === p)) {
|
||||||
|
@ -364,7 +365,7 @@ const PlayerButton = ({
|
||||||
|
|
||||||
export const ShuffleButton = (
|
export const ShuffleButton = (
|
||||||
player: MprisPlayer,
|
player: MprisPlayer,
|
||||||
colors: Var<any>,
|
colors: Var<Colors>,
|
||||||
) => PlayerButton({
|
) => PlayerButton({
|
||||||
player,
|
player,
|
||||||
colors,
|
colors,
|
||||||
|
@ -384,7 +385,7 @@ export const ShuffleButton = (
|
||||||
|
|
||||||
export const LoopButton = (
|
export const LoopButton = (
|
||||||
player: MprisPlayer,
|
player: MprisPlayer,
|
||||||
colors: Var<any>,
|
colors: Var<Colors>,
|
||||||
) => PlayerButton({
|
) => PlayerButton({
|
||||||
player,
|
player,
|
||||||
colors,
|
colors,
|
||||||
|
@ -408,7 +409,7 @@ export const LoopButton = (
|
||||||
|
|
||||||
export const PlayPauseButton = (
|
export const PlayPauseButton = (
|
||||||
player: MprisPlayer,
|
player: MprisPlayer,
|
||||||
colors: Var<any>,
|
colors: Var<Colors>,
|
||||||
) => PlayerButton({
|
) => PlayerButton({
|
||||||
player,
|
player,
|
||||||
colors,
|
colors,
|
||||||
|
@ -432,7 +433,7 @@ export const PlayPauseButton = (
|
||||||
|
|
||||||
export const PreviousButton = (
|
export const PreviousButton = (
|
||||||
player: MprisPlayer,
|
player: MprisPlayer,
|
||||||
colors: Var<any>,
|
colors: Var<Colors>,
|
||||||
) => PlayerButton({
|
) => PlayerButton({
|
||||||
player,
|
player,
|
||||||
colors,
|
colors,
|
||||||
|
@ -452,7 +453,7 @@ export const PreviousButton = (
|
||||||
|
|
||||||
export const NextButton = (
|
export const NextButton = (
|
||||||
player: MprisPlayer,
|
player: MprisPlayer,
|
||||||
colors: Var<any>,
|
colors: Var<Colors>,
|
||||||
) => PlayerButton({
|
) => PlayerButton({
|
||||||
player,
|
player,
|
||||||
colors,
|
colors,
|
||||||
|
|
|
@ -12,14 +12,13 @@ const SPACING = 8;
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import { MprisPlayer } from 'types/service/mpris.ts';
|
import { MprisPlayer } from 'types/service/mpris.ts';
|
||||||
import AgsOverlay from 'types/widgets/overlay.ts';
|
|
||||||
import { Variable as Var } from 'types/variable';
|
import { Variable as Var } from 'types/variable';
|
||||||
import AgsBox from 'types/widgets/box.ts';
|
import { Colors, PlayerBox, PlayerOverlay } from 'global-types';
|
||||||
|
|
||||||
|
|
||||||
const Top = (
|
const Top = (
|
||||||
player: MprisPlayer,
|
player: MprisPlayer,
|
||||||
overlay: AgsOverlay,
|
overlay: PlayerOverlay,
|
||||||
) => Box({
|
) => Box({
|
||||||
class_name: 'top',
|
class_name: 'top',
|
||||||
hpack: 'start',
|
hpack: 'start',
|
||||||
|
@ -32,7 +31,7 @@ const Top = (
|
||||||
|
|
||||||
const Center = (
|
const Center = (
|
||||||
player: MprisPlayer,
|
player: MprisPlayer,
|
||||||
colors: Var<any>,
|
colors: Var<Colors>,
|
||||||
) => Box({
|
) => Box({
|
||||||
class_name: 'center',
|
class_name: 'center',
|
||||||
|
|
||||||
|
@ -65,7 +64,7 @@ const Center = (
|
||||||
|
|
||||||
const Bottom = (
|
const Bottom = (
|
||||||
player: MprisPlayer,
|
player: MprisPlayer,
|
||||||
colors: Var<any>,
|
colors: Var<Colors>,
|
||||||
) => Box({
|
) => Box({
|
||||||
class_name: 'bottom',
|
class_name: 'bottom',
|
||||||
|
|
||||||
|
@ -88,8 +87,8 @@ const Bottom = (
|
||||||
|
|
||||||
const PlayerBox = (
|
const PlayerBox = (
|
||||||
player: MprisPlayer,
|
player: MprisPlayer,
|
||||||
colors: Var<any>,
|
colors: Var<Colors>,
|
||||||
overlay: AgsOverlay,
|
overlay: PlayerOverlay,
|
||||||
) => {
|
) => {
|
||||||
const widget = mpris.CoverArt(player, colors, {
|
const widget = mpris.CoverArt(player, colors, {
|
||||||
class_name: `player ${player.name}`,
|
class_name: `player ${player.name}`,
|
||||||
|
@ -107,14 +106,9 @@ const PlayerBox = (
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const content = PlayerGesture({
|
const content = PlayerGesture({
|
||||||
attribute: {
|
setup: (self: PlayerOverlay) => {
|
||||||
players: new Map(),
|
|
||||||
setup: false,
|
|
||||||
},
|
|
||||||
|
|
||||||
setup: (self) => {
|
|
||||||
self
|
self
|
||||||
.hook(Mpris, (_: AgsOverlay, bus_name: string) => {
|
.hook(Mpris, (_, bus_name) => {
|
||||||
const players = self.attribute.players;
|
const players = self.attribute.players;
|
||||||
|
|
||||||
if (players.has(bus_name)) {
|
if (players.has(bus_name)) {
|
||||||
|
@ -136,11 +130,16 @@ export default () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the one on top so we can move it up later
|
// Get the one on top so we can move it up later
|
||||||
const previousFirst = self.overlays.at(-1);
|
const previousFirst = self.overlays.at(-1) as PlayerBox;
|
||||||
|
|
||||||
// Make the new player
|
// Make the new player
|
||||||
const player = Mpris.getPlayer(bus_name);
|
const player = Mpris.getPlayer(bus_name);
|
||||||
const Colors = Variable(null);
|
const colorsVar = Variable({
|
||||||
|
imageAccent: '#6b4fa2',
|
||||||
|
buttonAccent: '#ecdcff',
|
||||||
|
buttonText: '#25005a',
|
||||||
|
hoverAccent: '#d4baff',
|
||||||
|
});
|
||||||
|
|
||||||
if (!player) {
|
if (!player) {
|
||||||
return;
|
return;
|
||||||
|
@ -148,14 +147,10 @@ export default () => {
|
||||||
|
|
||||||
players.set(
|
players.set(
|
||||||
bus_name,
|
bus_name,
|
||||||
PlayerBox(
|
PlayerBox(player, colorsVar, self),
|
||||||
player,
|
|
||||||
Colors,
|
|
||||||
content.get_children()[0] as AgsOverlay,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
self.overlays = Array.from(players.values())
|
self.overlays = Array.from(players.values())
|
||||||
.map((widget) => widget) as Array<AgsBox>;
|
.map((widget) => widget) as PlayerBox[];
|
||||||
|
|
||||||
const includes = self.attribute
|
const includes = self.attribute
|
||||||
.includesWidget(previousFirst);
|
.includesWidget(previousFirst);
|
||||||
|
@ -174,7 +169,7 @@ export default () => {
|
||||||
}
|
}
|
||||||
}, 'player-added')
|
}, 'player-added')
|
||||||
|
|
||||||
.hook(Mpris, (_: AgsOverlay, bus_name: string) => {
|
.hook(Mpris, (_, bus_name) => {
|
||||||
const players = self.attribute.players;
|
const players = self.attribute.players;
|
||||||
|
|
||||||
if (!bus_name || !players.has(bus_name)) {
|
if (!bus_name || !players.has(bus_name)) {
|
||||||
|
@ -182,12 +177,12 @@ export default () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the one on top so we can move it up later
|
// Get the one on top so we can move it up later
|
||||||
const previousFirst = self.overlays.at(-1);
|
const previousFirst = self.overlays.at(-1) as PlayerBox;
|
||||||
|
|
||||||
// Remake overlays without deleted one
|
// Remake overlays without deleted one
|
||||||
players.delete(bus_name);
|
players.delete(bus_name);
|
||||||
self.overlays = Array.from(players.values())
|
self.overlays = Array.from(players.values())
|
||||||
.map((widget) => widget) as Array<AgsBox>;
|
.map((widget) => widget) as PlayerBox[];
|
||||||
|
|
||||||
// Move previousFirst on top again
|
// Move previousFirst on top again
|
||||||
const includes = self.attribute
|
const includes = self.attribute
|
||||||
|
|
|
@ -23,7 +23,7 @@ Audio.connect('speaker-changed', () => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Audio.speaker.stream.is_muted) {
|
if (Audio.speaker.stream?.is_muted) {
|
||||||
SpeakerIcon.value = speakerIcons[0];
|
SpeakerIcon.value = speakerIcons[0];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -43,7 +43,7 @@ Audio.connect('microphone-changed', () => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Audio.microphone.stream.is_muted) {
|
if (Audio.microphone.stream?.is_muted) {
|
||||||
MicIcon.value = micIcons[0];
|
MicIcon.value = micIcons[0];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
import App from 'resource:///com/github/Aylur/ags/app.js';
|
import App from 'resource:///com/github/Aylur/ags/app.js';
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import AgsWindow from 'types/widgets/window';
|
import { PopupWindow } from 'global-types';
|
||||||
|
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
(Array.from(App.windows) as Array<[string, AgsWindow]>)
|
(Array.from(App.windows) as Array<[string, PopupWindow]>)
|
||||||
.filter((w) => w[1].attribute?.close_on_unfocus &&
|
.filter((w) =>
|
||||||
w[1].attribute?.close_on_unfocus !== 'stay')
|
w[1].attribute.close_on_unfocus &&
|
||||||
|
w[1].attribute.close_on_unfocus !== 'stay')
|
||||||
.forEach((w) => {
|
.forEach((w) => {
|
||||||
App.closeWindow(w[0]);
|
App.closeWindow(w[0]);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,80 +1,68 @@
|
||||||
import Variable from 'resource:///com/github/Aylur/ags/variable.js';
|
import { register } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
|
import Gtk from 'gi://Gtk?version=3.0';
|
||||||
|
import Gdk from 'gi://Gdk?version=3.0';
|
||||||
|
|
||||||
import { EventBox } from 'resource:///com/github/Aylur/ags/widget.js';
|
// Types
|
||||||
|
import { BaseProps, Widget } from 'types/widgets/widget';
|
||||||
|
type EventHandler<Self> = (self: Self, event: Gdk.Event) => boolean | unknown;
|
||||||
|
|
||||||
const { Gtk, Gdk } = imports.gi;
|
export type CursorBoxProps<
|
||||||
const display = Gdk.Display.get_default();
|
Child extends Gtk.Widget,
|
||||||
|
Attr = unknown,
|
||||||
|
Self = CursorBox<Child, Attr>,
|
||||||
|
> = BaseProps<Self, Gtk.EventBox.ConstructorProperties & {
|
||||||
|
child?: Child
|
||||||
|
on_hover?: EventHandler<Self>
|
||||||
|
on_hover_lost?: EventHandler<Self>
|
||||||
|
|
||||||
import * as EventBoxTypes from 'types/widgets/eventbox';
|
on_scroll_up?: EventHandler<Self>
|
||||||
type CursorBox = EventBoxTypes.EventBoxProps & {
|
on_scroll_down?: EventHandler<Self>
|
||||||
on_primary_click_release?(self: EventBoxTypes.default): void;
|
|
||||||
on_hover?(self: EventBoxTypes.default): void;
|
on_primary_click?: EventHandler<Self>
|
||||||
on_hover_lost?(self: EventBoxTypes.default): void;
|
on_middle_click?: EventHandler<Self>
|
||||||
};
|
on_secondary_click?: EventHandler<Self>
|
||||||
|
|
||||||
|
on_primary_click_release?: EventHandler<Self>
|
||||||
|
on_middle_click_release?: EventHandler<Self>
|
||||||
|
on_secondary_click_release?: EventHandler<Self>
|
||||||
|
}, Attr>;
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
export interface CursorBox<Child, Attr> extends Widget<Attr> { }
|
||||||
|
|
||||||
|
|
||||||
export default ({
|
export class CursorBox<Child extends Gtk.Widget, Attr> extends Gtk.EventBox {
|
||||||
on_primary_click_release = () => {/**/},
|
static {
|
||||||
on_hover = () => {/**/},
|
register(this, {
|
||||||
on_hover_lost = () => {/**/},
|
properties: {
|
||||||
attribute,
|
'on-clicked': ['jsobject', 'rw'],
|
||||||
...props
|
|
||||||
}: CursorBox) => {
|
|
||||||
// Make this variable to know if the function should
|
|
||||||
// be executed depending on where the click is released
|
|
||||||
const CanRun = Variable(true);
|
|
||||||
const Disabled = Variable(false);
|
|
||||||
|
|
||||||
const cursorBox = EventBox({
|
'on-hover': ['jsobject', 'rw'],
|
||||||
...props,
|
'on-hover-lost': ['jsobject', 'rw'],
|
||||||
|
|
||||||
attribute: {
|
'on-scroll-up': ['jsobject', 'rw'],
|
||||||
...attribute,
|
'on-scroll-down': ['jsobject', 'rw'],
|
||||||
disabled: Disabled,
|
|
||||||
|
'on-primary-click': ['jsobject', 'rw'],
|
||||||
|
'on-secondary-click': ['jsobject', 'rw'],
|
||||||
|
'on-middle-click': ['jsobject', 'rw'],
|
||||||
|
|
||||||
|
'on-primary-click-release': ['jsobject', 'rw'],
|
||||||
|
'on-secondary-click-release': ['jsobject', 'rw'],
|
||||||
|
'on-middle-click-release': ['jsobject', 'rw'],
|
||||||
},
|
},
|
||||||
|
});
|
||||||
on_primary_click_release: (self) => {
|
|
||||||
// Every click, do a one shot connect to
|
|
||||||
// CanRun to wait for location of click
|
|
||||||
const id = CanRun.connect('changed', () => {
|
|
||||||
if (CanRun.value && !Disabled.value) {
|
|
||||||
on_primary_click_release(self);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CanRun.disconnect(id);
|
constructor(props: CursorBoxProps<Child, Attr> = {}) {
|
||||||
});
|
super(props as Gtk.EventBox.ConstructorProperties);
|
||||||
},
|
this.add_events(Gdk.EventMask.SCROLL_MASK);
|
||||||
|
this.add_events(Gdk.EventMask.SMOOTH_SCROLL_MASK);
|
||||||
|
|
||||||
// OnHover
|
// Gesture stuff
|
||||||
}).on('enter-notify-event', (self) => {
|
const gesture = Gtk.GestureLongPress.new(this);
|
||||||
on_hover(self);
|
|
||||||
|
|
||||||
if (!display) {
|
this.hook(gesture, () => {
|
||||||
return;
|
|
||||||
}
|
|
||||||
self.window.set_cursor(Gdk.Cursor.new_from_name(
|
|
||||||
display,
|
|
||||||
Disabled.value ?
|
|
||||||
'not-allowed' :
|
|
||||||
'pointer',
|
|
||||||
));
|
|
||||||
self.toggleClassName('hover', true);
|
|
||||||
|
|
||||||
// OnHoverLost
|
|
||||||
}).on('leave-notify-event', (self) => {
|
|
||||||
on_hover_lost(self);
|
|
||||||
|
|
||||||
self.window.set_cursor(null);
|
|
||||||
self.toggleClassName('hover', false);
|
|
||||||
|
|
||||||
// Disabled class
|
|
||||||
}).hook(Disabled, (self) => {
|
|
||||||
self.toggleClassName('disabled', Disabled.value);
|
|
||||||
});
|
|
||||||
|
|
||||||
const gesture = Gtk.GestureLongPress.new(cursorBox);
|
|
||||||
|
|
||||||
cursorBox.hook(gesture, () => {
|
|
||||||
const pointer = gesture.get_point(null);
|
const pointer = gesture.get_point(null);
|
||||||
const x = pointer[1];
|
const x = pointer[1];
|
||||||
const y = pointer[2];
|
const y = pointer[2];
|
||||||
|
@ -83,11 +71,198 @@ export default ({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CanRun.value = !(
|
this.#canRun.value = !(
|
||||||
x > cursorBox.get_allocated_width() ||
|
x > this.get_allocated_width() ||
|
||||||
y > cursorBox.get_allocated_height()
|
y > this.get_allocated_height()
|
||||||
);
|
);
|
||||||
}, 'end');
|
}, 'end');
|
||||||
|
|
||||||
return cursorBox;
|
this.connect('enter-notify-event', (_, event: Gdk.Event) => {
|
||||||
};
|
this.set_state_flags(Gtk.StateFlags.PRELIGHT, false);
|
||||||
|
|
||||||
|
if (!this.#display) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.window.set_cursor(Gdk.Cursor.new_from_name(
|
||||||
|
this.#display,
|
||||||
|
this.#disabled.value ?
|
||||||
|
'not-allowed' :
|
||||||
|
'pointer',
|
||||||
|
));
|
||||||
|
|
||||||
|
return this.on_hover?.(this, event);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.connect('leave-notify-event', (_, event: Gdk.Event) => {
|
||||||
|
this.unset_state_flags(Gtk.StateFlags.PRELIGHT);
|
||||||
|
|
||||||
|
this.window.set_cursor(null);
|
||||||
|
|
||||||
|
return this.on_hover_lost?.(this, event);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.connect('button-press-event', (_, event: Gdk.Event) => {
|
||||||
|
this.set_state_flags(Gtk.StateFlags.ACTIVE, false);
|
||||||
|
if (this.#disabled.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.get_button()[1] === Gdk.BUTTON_PRIMARY) {
|
||||||
|
return this.on_primary_click?.(this, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (event.get_button()[1] === Gdk.BUTTON_MIDDLE) {
|
||||||
|
return this.on_middle_click?.(this, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (event.get_button()[1] === Gdk.BUTTON_SECONDARY) {
|
||||||
|
return this.on_secondary_click?.(this, event);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.connect('button-release-event', (_, event: Gdk.Event) => {
|
||||||
|
this.unset_state_flags(Gtk.StateFlags.ACTIVE);
|
||||||
|
if (this.#disabled.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.get_button()[1] === Gdk.BUTTON_PRIMARY) {
|
||||||
|
// Every click, do a one shot connect to
|
||||||
|
// CanRun to wait for location of click
|
||||||
|
const id = this.#canRun.connect('changed', () => {
|
||||||
|
if (this.#canRun.value) {
|
||||||
|
this.on_primary_click_release?.(this, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.#canRun.disconnect(id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (event.get_button()[1] === Gdk.BUTTON_MIDDLE) {
|
||||||
|
return this.on_middle_click_release?.(this, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (event.get_button()[1] === Gdk.BUTTON_SECONDARY) {
|
||||||
|
return this.on_secondary_click_release?.(this, event);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.connect('scroll-event', (_, event: Gdk.Event) => {
|
||||||
|
if (event.get_scroll_deltas()[2] < 0) {
|
||||||
|
return this.on_scroll_up?.(this, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (event.get_scroll_deltas()[2] > 0) {
|
||||||
|
return this.on_scroll_down?.(this, event);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#display = Gdk.Display.get_default();
|
||||||
|
|
||||||
|
// Make this variable to know if the function should
|
||||||
|
// be executed depending on where the click is released
|
||||||
|
#canRun = Variable(true);
|
||||||
|
#disabled = Variable(false);
|
||||||
|
|
||||||
|
get disabled() {
|
||||||
|
return this.#disabled.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
set disabled(value: boolean) {
|
||||||
|
this.#disabled.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
get child() {
|
||||||
|
return super.child as Child;
|
||||||
|
}
|
||||||
|
|
||||||
|
set child(child: Child) {
|
||||||
|
super.child = child;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
get on_hover() {
|
||||||
|
return this._get('on-hover');
|
||||||
|
}
|
||||||
|
|
||||||
|
set on_hover(callback: EventHandler<this>) {
|
||||||
|
this._set('on-hover', callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
get on_hover_lost() {
|
||||||
|
return this._get('on-hover-lost');
|
||||||
|
}
|
||||||
|
|
||||||
|
set on_hover_lost(callback: EventHandler<this>) {
|
||||||
|
this._set('on-hover-lost', callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
get on_scroll_up() {
|
||||||
|
return this._get('on-scroll-up');
|
||||||
|
}
|
||||||
|
|
||||||
|
set on_scroll_up(callback: EventHandler<this>) {
|
||||||
|
this._set('on-scroll-up', callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
get on_scroll_down() {
|
||||||
|
return this._get('on-scroll-down');
|
||||||
|
}
|
||||||
|
|
||||||
|
set on_scroll_down(callback: EventHandler<this>) {
|
||||||
|
this._set('on-scroll-down', callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
get on_primary_click() {
|
||||||
|
return this._get('on-primary-click');
|
||||||
|
}
|
||||||
|
|
||||||
|
set on_primary_click(callback: EventHandler<this>) {
|
||||||
|
this._set('on-primary-click', callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
get on_middle_click() {
|
||||||
|
return this._get('on-middle-click');
|
||||||
|
}
|
||||||
|
|
||||||
|
set on_middle_click(callback: EventHandler<this>) {
|
||||||
|
this._set('on-middle-click', callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
get on_secondary_click() {
|
||||||
|
return this._get('on-secondary-click');
|
||||||
|
}
|
||||||
|
|
||||||
|
set on_secondary_click(callback: EventHandler<this>) {
|
||||||
|
this._set('on-secondary-click', callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
get on_primary_click_release() {
|
||||||
|
return this._get('on-primary-click-release');
|
||||||
|
}
|
||||||
|
|
||||||
|
set on_primary_click_release(callback: EventHandler<this>) {
|
||||||
|
this._set('on-primary-click-release', callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
get on_middle_click_release() {
|
||||||
|
return this._get('on-middle-click-release');
|
||||||
|
}
|
||||||
|
|
||||||
|
set on_middle_click_release(callback: EventHandler<this>) {
|
||||||
|
this._set('on-middle-click-release', callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
get on_secondary_click_release() {
|
||||||
|
return this._get('on-secondary-click-release');
|
||||||
|
}
|
||||||
|
|
||||||
|
set on_secondary_click_release(callback: EventHandler<this>) {
|
||||||
|
this._set('on-secondary-click-release', callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default <Child extends Gtk.Widget, Attr>(
|
||||||
|
props?: CursorBoxProps<Child, Attr>,
|
||||||
|
) => new CursorBox(props ?? {});
|
||||||
|
|
|
@ -2,33 +2,61 @@ import App from 'resource:///com/github/Aylur/ags/app.js';
|
||||||
import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
|
import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js';
|
||||||
import Variable from 'resource:///com/github/Aylur/ags/variable.js';
|
import Variable from 'resource:///com/github/Aylur/ags/variable.js';
|
||||||
|
|
||||||
import { Box, Overlay, Window } from 'resource:///com/github/Aylur/ags/widget.js';
|
import { Box, Overlay, register } from 'resource:///com/github/Aylur/ags/widget.js';
|
||||||
import { timeout } from 'resource:///com/github/Aylur/ags/utils.js';
|
import { timeout } from 'resource:///com/github/Aylur/ags/utils.js';
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
|
import { Window } from 'resource:///com/github/Aylur/ags/widgets/window.js';
|
||||||
import { Allocation, Widget } from 'types/@girs/gtk-3.0/gtk-3.0.cjs';
|
import { Allocation, Widget } from 'types/@girs/gtk-3.0/gtk-3.0.cjs';
|
||||||
import { RevealerProps } from 'types/widgets/revealer';
|
import { Variable as Var } from 'types/variable';
|
||||||
import { WindowProps } from 'types/widgets/window';
|
|
||||||
import AgsWindow from 'types/widgets/window';
|
import {
|
||||||
import AgsBox from 'types/widgets/box';
|
CloseType,
|
||||||
import AgsOverlay from 'types/widgets/overlay';
|
BoxGeneric,
|
||||||
import { Binding } from 'types/service';
|
OverlayGeneric,
|
||||||
type PopupWindow = WindowProps & {
|
PopupChild,
|
||||||
transition?: RevealerProps['transition']
|
PopupWindowProps,
|
||||||
transition_duration?: number
|
} from 'global-types';
|
||||||
bezier?: string
|
|
||||||
on_open?(self: AgsWindow): void
|
|
||||||
on_close?(self: AgsWindow): void
|
|
||||||
blur?: boolean
|
|
||||||
close_on_unfocus?: 'none' | 'stay' | 'released' | 'clicked'
|
|
||||||
anchor?: Array<string>
|
|
||||||
name: string
|
|
||||||
};
|
|
||||||
|
|
||||||
// FIXME: deal with overlay children?
|
// FIXME: deal with overlay children?
|
||||||
// TODO: make this a new class to be able to edit props
|
// TODO: make props changes affect the widget
|
||||||
|
|
||||||
export default ({
|
|
||||||
|
export class PopupWindow<
|
||||||
|
Child extends Widget,
|
||||||
|
Attr,
|
||||||
|
> extends Window<Child, Attr> {
|
||||||
|
static {
|
||||||
|
register(this, {
|
||||||
|
properties: {
|
||||||
|
content: ['widget', 'rw'],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#content: Var<Widget>;
|
||||||
|
#antiClip: Var<boolean>;
|
||||||
|
#needsAnticlipping: boolean;
|
||||||
|
#close_on_unfocus: CloseType;
|
||||||
|
|
||||||
|
get content() {
|
||||||
|
return this.#content.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
set content(value: Widget) {
|
||||||
|
this.#content.value = value;
|
||||||
|
this.child.show_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
get close_on_unfocus() {
|
||||||
|
return this.#close_on_unfocus;
|
||||||
|
}
|
||||||
|
|
||||||
|
set close_on_unfocus(value: 'none' | 'stay' | 'released' | 'clicked') {
|
||||||
|
this.#close_on_unfocus = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor({
|
||||||
transition = 'slide_down',
|
transition = 'slide_down',
|
||||||
transition_duration = 800,
|
transition_duration = 800,
|
||||||
bezier = 'cubic-bezier(0.68, -0.4, 0.32, 1.4)',
|
bezier = 'cubic-bezier(0.68, -0.4, 0.32, 1.4)',
|
||||||
|
@ -37,82 +65,31 @@ export default ({
|
||||||
|
|
||||||
// Window props
|
// Window props
|
||||||
name,
|
name,
|
||||||
child = Box(),
|
|
||||||
visible = false,
|
visible = false,
|
||||||
anchor = [],
|
anchor = [],
|
||||||
layer = 'overlay',
|
layer = 'overlay',
|
||||||
|
attribute,
|
||||||
|
content = Box(),
|
||||||
blur = false,
|
blur = false,
|
||||||
close_on_unfocus = 'released',
|
close_on_unfocus = 'released',
|
||||||
...props
|
...rest
|
||||||
}: PopupWindow) => {
|
}: PopupWindowProps<Child, Attr>) {
|
||||||
const Child = Variable(child);
|
|
||||||
const AntiClip = Variable(false);
|
|
||||||
|
|
||||||
const needsAnticlipping = bezier.match(/-[0-9]/) !== null &&
|
const needsAnticlipping = bezier.match(/-[0-9]/) !== null &&
|
||||||
transition !== 'crossfade';
|
transition !== 'crossfade';
|
||||||
|
const contentVar = Variable(Box() as Widget);
|
||||||
|
const antiClip = Variable(false);
|
||||||
|
|
||||||
const attribute = {
|
if (content) {
|
||||||
set_x_pos: (
|
contentVar.value = content;
|
||||||
alloc: Allocation,
|
|
||||||
side = 'right' as 'left' | 'right',
|
|
||||||
) => {
|
|
||||||
const window = App.getWindow(name) as AgsWindow;
|
|
||||||
|
|
||||||
if (!window) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const width = window.get_display()
|
super({
|
||||||
.get_monitor_at_point(alloc.x, alloc.y)
|
...rest,
|
||||||
.get_geometry().width;
|
|
||||||
|
|
||||||
window.margins = [
|
|
||||||
window.margins[0],
|
|
||||||
|
|
||||||
side === 'right' ?
|
|
||||||
(width - alloc.x - alloc.width) :
|
|
||||||
window.margins[1],
|
|
||||||
|
|
||||||
window.margins[2],
|
|
||||||
|
|
||||||
side === 'right' ?
|
|
||||||
window.margins[3] :
|
|
||||||
(alloc.x - alloc.width),
|
|
||||||
];
|
|
||||||
},
|
|
||||||
|
|
||||||
get_child: () => Child.value,
|
|
||||||
|
|
||||||
set_child: (new_child: Widget) => {
|
|
||||||
Child.value = new_child;
|
|
||||||
App.getWindow(name)?.child.show_all();
|
|
||||||
},
|
|
||||||
|
|
||||||
// This is for my custom pointers.ts
|
|
||||||
close_on_unfocus,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (transition === 'none') {
|
|
||||||
return Window({
|
|
||||||
name,
|
name,
|
||||||
layer,
|
visible,
|
||||||
anchor,
|
anchor,
|
||||||
visible: false,
|
|
||||||
...props,
|
|
||||||
attribute,
|
|
||||||
child: Child.bind(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const window = Window({
|
|
||||||
name,
|
|
||||||
layer,
|
layer,
|
||||||
anchor,
|
|
||||||
visible: false,
|
|
||||||
...props,
|
|
||||||
|
|
||||||
attribute,
|
attribute,
|
||||||
|
|
||||||
setup: () => {
|
setup: () => {
|
||||||
// Add way to make window open on startup
|
// Add way to make window open on startup
|
||||||
const id = App.connect('config-parsed', () => {
|
const id = App.connect('config-parsed', () => {
|
||||||
|
@ -128,7 +105,6 @@ export default ({
|
||||||
`keyword layerrule blur,${name}`);
|
`keyword layerrule blur,${name}`);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
child: Overlay({
|
child: Overlay({
|
||||||
overlays: [Box({
|
overlays: [Box({
|
||||||
css: `
|
css: `
|
||||||
|
@ -177,7 +153,7 @@ export default ({
|
||||||
// so we can't change the order
|
// so we can't change the order
|
||||||
if (anchor.length !== 0) {
|
if (anchor.length !== 0) {
|
||||||
for (const ch of self.children) {
|
for (const ch of self.children) {
|
||||||
if (ch !== Child.value) {
|
if (ch !== contentVar.value) {
|
||||||
self.reorder_child(ch, position);
|
self.reorder_child(ch, position);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -186,7 +162,7 @@ export default ({
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.hook(AntiClip, () => {
|
self.hook(antiClip, () => {
|
||||||
if (transition === 'slide_down') {
|
if (transition === 'slide_down') {
|
||||||
self.vertical = true;
|
self.vertical = true;
|
||||||
reorder_child(-1);
|
reorder_child(-1);
|
||||||
|
@ -207,7 +183,7 @@ export default ({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
children: Child.bind().transform((v) => {
|
children: contentVar.bind().transform((v) => {
|
||||||
if (needsAnticlipping) {
|
if (needsAnticlipping) {
|
||||||
return [
|
return [
|
||||||
// Add an anticlip widget when unanchored
|
// Add an anticlip widget when unanchored
|
||||||
|
@ -218,7 +194,7 @@ export default ({
|
||||||
min-width: 100px;
|
min-width: 100px;
|
||||||
padding: 2px;
|
padding: 2px;
|
||||||
`,
|
`,
|
||||||
visible: AntiClip.bind(),
|
visible: antiClip.bind(),
|
||||||
}),
|
}),
|
||||||
v,
|
v,
|
||||||
Box({
|
Box({
|
||||||
|
@ -227,25 +203,25 @@ export default ({
|
||||||
min-width: 100px;
|
min-width: 100px;
|
||||||
padding: 2px;
|
padding: 2px;
|
||||||
`,
|
`,
|
||||||
visible: AntiClip.bind(),
|
visible: antiClip.bind(),
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return [v];
|
return [v];
|
||||||
}
|
}
|
||||||
}) as Binding<any, any, Widget[]>,
|
}) as PopupChild,
|
||||||
})],
|
})],
|
||||||
|
|
||||||
setup: (self) => {
|
setup: (self) => {
|
||||||
self.on('get-child-position', (_, ch) => {
|
self.on('get-child-position', (_, ch) => {
|
||||||
const overlay = (Child.value as Widget)
|
const overlay = contentVar.value
|
||||||
.get_parent() as AgsOverlay;
|
.get_parent() as OverlayGeneric;
|
||||||
|
|
||||||
if (ch === overlay) {
|
if (ch === overlay) {
|
||||||
const alloc = overlay.get_allocation();
|
const alloc = overlay.get_allocation();
|
||||||
|
|
||||||
(self.child as AgsBox).css = `
|
(self.child as BoxGeneric).css = `
|
||||||
min-height: ${alloc.height}px;
|
min-height: ${alloc.height}px;
|
||||||
min-width: ${alloc.width}px;
|
min-width: ${alloc.width}px;
|
||||||
`;
|
`;
|
||||||
|
@ -265,23 +241,24 @@ export default ({
|
||||||
|
|
||||||
self.hook(App, (_, currentName, isOpen) => {
|
self.hook(App, (_, currentName, isOpen) => {
|
||||||
if (currentName === name) {
|
if (currentName === name) {
|
||||||
const overlay = (Child.value as Widget)
|
const overlay = contentVar.value
|
||||||
.get_parent() as AgsOverlay;
|
.get_parent() as OverlayGeneric;
|
||||||
|
|
||||||
const alloc = overlay.get_allocation();
|
const alloc = overlay.get_allocation();
|
||||||
const height = needsAnticlipping ?
|
const height = antiClip ?
|
||||||
alloc.height + 100 + 10 :
|
alloc.height + 100 + 10 :
|
||||||
alloc.height + 10;
|
alloc.height + 10;
|
||||||
|
|
||||||
if (needsAnticlipping) {
|
if (needsAnticlipping) {
|
||||||
AntiClip.value = true;
|
antiClip.value = true;
|
||||||
|
|
||||||
const thisTimeout = timeout(
|
const thisTimeout = timeout(
|
||||||
transition_duration,
|
transition_duration,
|
||||||
() => {
|
() => {
|
||||||
// Only run the timeout if there isn't a newer timeout
|
// Only run the timeout if there isn't a newer timeout
|
||||||
if (thisTimeout === currentTimeout) {
|
if (thisTimeout ===
|
||||||
AntiClip.value = false;
|
currentTimeout) {
|
||||||
|
antiClip.value = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -342,7 +319,7 @@ export default ({
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isOpen) {
|
if (isOpen) {
|
||||||
on_open(window);
|
on_open(this);
|
||||||
|
|
||||||
// To get the animation, we need to set the css
|
// To get the animation, we need to set the css
|
||||||
// to hide the widget and then timeout to have
|
// to hide the widget and then timeout to have
|
||||||
|
@ -351,16 +328,18 @@ export default ({
|
||||||
timeout(10, () => {
|
timeout(10, () => {
|
||||||
overlay.css = `
|
overlay.css = `
|
||||||
transition: margin
|
transition: margin
|
||||||
${transition_duration}ms ${bezier},
|
${transition_duration}ms
|
||||||
|
${bezier},
|
||||||
|
|
||||||
opacity
|
opacity
|
||||||
${transition_duration}ms ${bezier};
|
${transition_duration}ms
|
||||||
|
${bezier};
|
||||||
`;
|
`;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
timeout(transition_duration, () => {
|
timeout(transition_duration, () => {
|
||||||
on_close(window);
|
on_close(this);
|
||||||
});
|
});
|
||||||
|
|
||||||
overlay.css = `${css}
|
overlay.css = `${css}
|
||||||
|
@ -378,5 +357,36 @@ export default ({
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
return window;
|
this.#content = contentVar;
|
||||||
};
|
this.#close_on_unfocus = close_on_unfocus;
|
||||||
|
this.#needsAnticlipping = needsAnticlipping;
|
||||||
|
this.#antiClip = antiClip;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_x_pos(
|
||||||
|
alloc: Allocation,
|
||||||
|
side = 'right' as 'left' | 'right',
|
||||||
|
) {
|
||||||
|
const width = this.get_display()
|
||||||
|
.get_monitor_at_point(alloc.x, alloc.y)
|
||||||
|
.get_geometry().width;
|
||||||
|
|
||||||
|
this.margins = [
|
||||||
|
this.margins[0],
|
||||||
|
|
||||||
|
side === 'right' ?
|
||||||
|
(width - alloc.x - alloc.width) :
|
||||||
|
this.margins[1],
|
||||||
|
|
||||||
|
this.margins[2],
|
||||||
|
|
||||||
|
side === 'right' ?
|
||||||
|
this.margins[3] :
|
||||||
|
(alloc.x - alloc.width),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default <Child extends Widget, Attr>(
|
||||||
|
props: PopupWindowProps<Child, Attr>,
|
||||||
|
) => new PopupWindow(props);
|
||||||
|
|
|
@ -13,13 +13,19 @@ import CursorBox from '../misc/cursorbox.ts';
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import { Notification as NotifObj } from 'types/service/notifications.ts';
|
import { Notification as NotifObj } from 'types/service/notifications.ts';
|
||||||
import AgsEventBox from 'types/widgets/eventbox.ts';
|
import AgsEventBox from 'types/widgets/eventbox';
|
||||||
|
import { Widget } from 'types/@girs/gtk-3.0/gtk-3.0.cjs';
|
||||||
import { Client } from 'types/service/hyprland.ts';
|
import { Client } from 'types/service/hyprland.ts';
|
||||||
type NotificationWidget = {
|
type NotificationWidget = {
|
||||||
notif: NotifObj
|
notif: NotifObj
|
||||||
slideIn?: 'Left' | 'Right'
|
slideIn?: 'Left' | 'Right'
|
||||||
command?(): void
|
command?(): void
|
||||||
};
|
};
|
||||||
|
import {
|
||||||
|
EventBoxGeneric,
|
||||||
|
CursorBox as CBox,
|
||||||
|
} from 'global-types';
|
||||||
|
|
||||||
|
|
||||||
const setTime = (time: number) => {
|
const setTime = (time: number) => {
|
||||||
return GLib.DateTime
|
return GLib.DateTime
|
||||||
|
@ -27,13 +33,17 @@ const setTime = (time: number) => {
|
||||||
.format('%H:%M');
|
.format('%H:%M');
|
||||||
};
|
};
|
||||||
|
|
||||||
const getDragState = (box: AgsEventBox) => (box.get_parent()?.get_parent()
|
const getDragState = (box: EventBoxGeneric) => (box
|
||||||
?.get_parent()?.get_parent()?.get_parent() as AgsEventBox)
|
.get_parent()
|
||||||
|
?.get_parent()
|
||||||
|
?.get_parent()
|
||||||
|
?.get_parent()
|
||||||
|
?.get_parent() as AgsEventBox<Widget, { dragging: boolean }>)
|
||||||
?.attribute.dragging;
|
?.attribute.dragging;
|
||||||
|
|
||||||
|
|
||||||
const NotificationIcon = (notif: NotifObj) => {
|
const NotificationIcon = (notif: NotifObj) => {
|
||||||
let iconCmd = (box: AgsEventBox):void => {
|
let iconCmd = (box: CBox):void => {
|
||||||
console.log(box);
|
console.log(box);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -89,7 +99,9 @@ const NotificationIcon = (notif: NotifObj) => {
|
||||||
|
|
||||||
if (notif.image) {
|
if (notif.image) {
|
||||||
return CursorBox({
|
return CursorBox({
|
||||||
on_primary_click_release: iconCmd,
|
on_primary_click_release: (self) => {
|
||||||
|
iconCmd(self);
|
||||||
|
},
|
||||||
|
|
||||||
child: Box({
|
child: Box({
|
||||||
vpack: 'start',
|
vpack: 'start',
|
||||||
|
@ -120,7 +132,9 @@ const NotificationIcon = (notif: NotifObj) => {
|
||||||
|
|
||||||
|
|
||||||
return CursorBox({
|
return CursorBox({
|
||||||
on_primary_click_release: iconCmd,
|
on_primary_click_release: (self) => {
|
||||||
|
iconCmd(self);
|
||||||
|
},
|
||||||
|
|
||||||
child: Box({
|
child: Box({
|
||||||
vpack: 'start',
|
vpack: 'start',
|
||||||
|
@ -175,7 +189,7 @@ export const Notification = ({
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add body to notif
|
// Add body to notif
|
||||||
(notifWidget.child as AgsEventBox).add(Box({
|
(notifWidget.child as EventBoxGeneric).add(Box({
|
||||||
class_name: `notification ${notif.urgency}`,
|
class_name: `notification ${notif.urgency}`,
|
||||||
vexpand: false,
|
vexpand: false,
|
||||||
|
|
||||||
|
|
|
@ -21,5 +21,5 @@ export const NotifCenter = () => PopupWindow({
|
||||||
transition: 'slide_up',
|
transition: 'slide_up',
|
||||||
monitor: 1,
|
monitor: 1,
|
||||||
|
|
||||||
child: NotifCenterWidget(),
|
content: NotifCenterWidget(),
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,11 +8,11 @@ import { Notification, HasNotifs } from './base.ts';
|
||||||
import CursorBox from '../misc/cursorbox.ts';
|
import CursorBox from '../misc/cursorbox.ts';
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import AgsBox from 'types/widgets/box.ts';
|
|
||||||
import { Notification as NotifObj } from 'resource:///com/github/Aylur/ags/service/notifications.js';
|
import { Notification as NotifObj } from 'resource:///com/github/Aylur/ags/service/notifications.js';
|
||||||
|
import { BoxGeneric } from 'global-types';
|
||||||
|
|
||||||
|
|
||||||
const addNotif = (box: AgsBox, notif: NotifObj) => {
|
const addNotif = (box: BoxGeneric, notif: NotifObj) => {
|
||||||
if (notif) {
|
if (notif) {
|
||||||
const NewNotif = Notification({
|
const NewNotif = Notification({
|
||||||
notif,
|
notif,
|
||||||
|
@ -53,7 +53,7 @@ const NotificationList = () => Box({
|
||||||
}, 'notified')
|
}, 'notified')
|
||||||
|
|
||||||
.hook(Notifications, (box, id) => {
|
.hook(Notifications, (box, id) => {
|
||||||
const notif = (box.children as Array<AgsBox>)
|
const notif = (box.children as BoxGeneric[])
|
||||||
.find((ch) => ch.attribute.id === id);
|
.find((ch) => ch.attribute.id === id);
|
||||||
|
|
||||||
if (notif?.sensitive) {
|
if (notif?.sensitive) {
|
||||||
|
@ -73,7 +73,7 @@ const ClearButton = () => CursorBox({
|
||||||
|
|
||||||
setup: (self) => {
|
setup: (self) => {
|
||||||
self.hook(HasNotifs, () => {
|
self.hook(HasNotifs, () => {
|
||||||
self.attribute.disabled?.setValue(!HasNotifs.value);
|
self.disabled = !HasNotifs.value;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -18,5 +18,5 @@ export const NotifCenter = () => PopupWindow({
|
||||||
anchor: ['top', 'right'],
|
anchor: ['top', 'right'],
|
||||||
margins: [TOP_MARGIN, 0, 0, 0],
|
margins: [TOP_MARGIN, 0, 0, 0],
|
||||||
|
|
||||||
child: NotifCenterWidget(),
|
content: NotifCenterWidget(),
|
||||||
});
|
});
|
||||||
|
|
|
@ -61,5 +61,5 @@ export default () => PopupWindow({
|
||||||
transition: 'slide_up',
|
transition: 'slide_up',
|
||||||
transition_duration,
|
transition_duration,
|
||||||
bezier: 'ease',
|
bezier: 'ease',
|
||||||
child: OSDs(),
|
content: OSDs(),
|
||||||
});
|
});
|
||||||
|
|
|
@ -44,5 +44,5 @@ const PowermenuWidget = () => CenterBox({
|
||||||
|
|
||||||
export default () => PopupWindow({
|
export default () => PopupWindow({
|
||||||
name: 'powermenu',
|
name: 'powermenu',
|
||||||
child: PowermenuWidget(),
|
content: PowermenuWidget(),
|
||||||
});
|
});
|
||||||
|
|
|
@ -54,5 +54,5 @@ export default () => PopupWindow({
|
||||||
name: 'quick-settings',
|
name: 'quick-settings',
|
||||||
anchor: ['top', 'right'],
|
anchor: ['top', 'right'],
|
||||||
margins: [TOP_MARGIN, 0, 0, 0],
|
margins: [TOP_MARGIN, 0, 0, 0],
|
||||||
child: QuickSettingsWidget(),
|
content: QuickSettingsWidget(),
|
||||||
});
|
});
|
||||||
|
|
|
@ -10,7 +10,10 @@
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"noImplicitAny": false,
|
"noImplicitAny": false,
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"typeRoots": ["./types"],
|
"typeRoots": [
|
||||||
|
"./types",
|
||||||
|
"./global-types.d.ts"
|
||||||
|
],
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"forceConsistentCasingInFileNames": true
|
"forceConsistentCasingInFileNames": true
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue