Skip to content

Commit 6101382

Browse files
committed
feat: click-through toggle
1 parent 2746c62 commit 6101382

File tree

12 files changed

+164
-28
lines changed

12 files changed

+164
-28
lines changed

README.md

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ A Zebar configuration forked from [Neobrutal Zebar](https://github.com/adriankar
1414
- Multi-monitor support
1515
- Windows Taskbar integration (experimental)
1616
- Background effects (Acrylic, Blur, Mica)
17+
- Click-through ability (disable interactivity and cursor events to windows below)
1718

1819
## 🖼️ Showcase
1920

@@ -98,7 +99,15 @@ General configuration is defined in `config.json`, which ships together with the
9899
"enableErrorLogging": false
99100
},
100101
"backgroundEffect": "acrylic",
101-
"enableAutoTiling": true
102+
"enableAutoTiling": true,
103+
"clickThroughByDefault": false,
104+
"showFullDateByDefault": false,
105+
"showHeartButton": true,
106+
"showCpuSection": true,
107+
"showMemorySection": true,
108+
"showBatterySection": true,
109+
"showNetworkSection": true,
110+
"showWeatherSection": true
102111
}
103112
```
104113

@@ -326,15 +335,16 @@ In addition to colors, `config.css` provides variables that control other style
326335

327336
</details>
328337

329-
## 🎉 Background Effects
338+
## 🎉 Background Effects & Click-Through
330339

331340
> [!WARNING]
332-
> This feature does not work in Windows 11 (Currently, supports only Windows 10). To achieve similar background effects, use an external application like [Mica For Everyone](https://github.com/MicaForEveryone/MicaForEveryone).
341+
> Background effects do not work in Windows 11 (Currently, supports only Windows 10). To achieve similar background effects, use an external application like [Mica For Everyone](https://github.com/MicaForEveryone/MicaForEveryone).
342+
> Click-through works fine in all platforms, however note that it completely disables interactivity with the Zebar widget.
333343

334-
To enable background effects, you need to recompile Zebar with a modification. You must have Rust and Node.js installed on your system.
344+
To enable any of these two features, you need to recompile Zebar with a modification. You must have Rust and Node.js installed on your system.
335345

336346
1. Clone the Zebar repository: `git clone https://github.com/glzr-io/zebar.git`
337-
2. Navigate to `packages/desktop/capabilities/widget.json` and add the following permission:
347+
2. Navigate to `packages/desktop/capabilities/widget.json` and add the following two permissions (don't forget the trailing commas!):
338348

339349
```json
340350
{
@@ -347,7 +357,8 @@ To enable background effects, you need to recompile Zebar with a modification. Y
347357
"core:window:allow-set-position",
348358
"core:window:allow-set-size",
349359
"core:window:allow-set-title",
350-
"core:window:allow-set-effects" <--- ADD THIS
360+
"core:window:allow-set-effects", <--- ADD THIS
361+
"core:window:allow-set-ignore-cursor-events" <--- AND THIS
351362
]
352363
}
353364
```
@@ -373,7 +384,42 @@ pnpm run build
373384
> [!NOTE]
374385
> By default, Zebar uses the rust nightly channel. To install it properly, you need to run (after uninstalling nightly if you have it already installed) `rustup toolchain install nightly --allow-downgrade --profile minimal`, otherwise Zebar may not be able to build. If it still doesn't manage to build, try changing the channel in `rust-toolchain.toml` to `stable`.
375386
376-
After installation, you can enable background effects in `config.json`.
387+
After installation, follow these instructions:
388+
389+
### Enable Background Effects
390+
391+
In `config.json`, set the `backgroundEffect` field to one of the values provided by the schema.
392+
393+
### Enable Click-Through
394+
395+
To use click-through, you must modify the GlazeWM configuration.
396+
397+
- In `config.yaml`, add a new binding mode for click-through under `binding_modes`:
398+
399+
```yaml
400+
binding_modes:
401+
...
402+
403+
# Click-through mode disables interactivity
404+
- name: 'ct'
405+
```
406+
407+
The name of the binding mode **must** be `ct` for the commands to work properly.
408+
409+
- Add a keybinding to toggle click-through mode under `keybindings`:
410+
411+
```yaml
412+
keybindings:
413+
...
414+
415+
# Sends a signal to Zebar via the binding mode
416+
- commands: ['wm-enable-binding-mode --name ct', "wm-disable-binding-mode --name ct"]
417+
bindings: ['alt+shift+c']
418+
```
419+
420+
And now you can toggle click-through mode by pressing `Alt + Shift + C`.
421+
422+
`config.json` also provides `clickThroughByDefault` field to enable click-through mode by default on startup.
377423

378424
## 🧪 Taskbar Integration
379425

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
},
1414
"devDependencies": {
1515
"@eslint/js": "^9.34.0",
16-
"@lucide/svelte": "^0.541.0",
16+
"@lucide/svelte": "^0.561.0",
1717
"@sveltejs/adapter-auto": "^6.1.0",
1818
"@sveltejs/adapter-static": "^3.0.9",
1919
"@sveltejs/kit": "^2.31.1",

pnpm-lock.yaml

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/components/LeftGroup.svelte

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,16 @@
4343
<div class="flex flex-row gap-3 items-center">
4444
{#if config.showHeartButton}
4545
<Button class="text-zb-icon"
46-
><IconHeartFilled class="text-zb-icon" /></Button
46+
><IconHeartFilled
47+
class="text-zb-icon"
48+
onclick={() => {
49+
// Opens in a new msedge webview window. Can't open in the default
50+
// browser without additional ACL in tauri.
51+
window
52+
.open("https://github.com/blaiyz/neosoft-zebar", "_blank")
53+
?.focus();
54+
}}
55+
/></Button
4756
>
4857
{/if}
4958
{#if config.showMemorySection}

src/components/Workspaces.svelte

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@
77
import { providers } from "$lib/providers.svelte";
88
import { getWindows } from "$lib/utils/glaze_wm_utils.svelte";
99
import ArrowRightLeft from "@lucide/svelte/icons/arrow-right-left";
10+
import MousePointer2Off from "@lucide/svelte/icons/mouse-pointer-2-off";
1011
import type { Icon as IconType } from "@tabler/icons-svelte";
1112
import Background from "@tabler/icons-svelte/icons/background";
1213
import { flip } from "svelte/animate";
1314
import { fly } from "svelte/transition";
1415
import Button from "./Button.svelte";
1516
import SmoothDiv from "./SmoothDiv.svelte";
17+
import { toggleModes } from "$lib/binding_modes.svelte";
1618
1719
const getProcessIcon = (child: Window): IconType => {
1820
const possibleAppNames = [
@@ -84,30 +86,36 @@
8486
/>
8587
</button>
8688
<SmoothDiv outerClass="flex justify-end" innerClass="flex items-center">
87-
{#each glazewm.bindingModes as bindingMode (bindingMode.name)}
89+
{#if toggleModes.clickThrough}
90+
<span
91+
transition:fly={{ y: 20, duration: config.transitionDuration }}
92+
class="relative flex flex-row-reverse"
93+
>
94+
<MousePointer2Off
95+
class="{toggleModes.clickThrough
96+
? ''
97+
: 'absolute'} text-zb-click-through mx-1"
98+
/>
99+
</span>
100+
{/if}
101+
</SmoothDiv>
102+
<SmoothDiv outerClass="flex justify-end" innerClass="flex items-center">
103+
{#each glazewm.bindingModes.filter((mode) => mode.name !== "ct") as bindingMode (bindingMode.name)}
88104
<button
89105
transition:fly={{ y: 20, duration: config.transitionDuration }}
90106
animate:flip={{ duration: config.transitionDuration }}
91107
class="mx-[0.5rem]"
92108
onclick={() => {
93-
switch (bindingMode.name.toLowerCase()) {
94-
case "pause":
95-
glazewm!.runCommand("wm-disable-binding-mode --name pause");
96-
break;
97-
98-
case "resize":
99-
glazewm!.runCommand("wm-disable-binding-mode --name resize");
100-
break;
101-
102-
default:
103-
break;
104-
}
109+
glazewm!.runCommand(
110+
`wm-disable-binding-mode --name ${bindingMode.name}`
111+
);
105112
}}
106113
>
107114
{bindingMode.displayName ?? bindingMode.name}
108115
</button>
109116
{/each}
110117
</SmoothDiv>
118+
111119
{#if glazewm.displayedWorkspace}
112120
<SmoothDiv
113121
outerClass="flex justify-end"

src/lib/binding_modes.svelte.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { currentWidget } from "zebar";
2+
import { providers } from "./providers.svelte";
3+
import { untrack } from "svelte";
4+
import { config, configLoaded } from "./config.svelte";
5+
6+
const bindingModes = $derived(providers.glazewm?.bindingModes || []);
7+
const clickThroughBindingMode = $derived(
8+
bindingModes.find((mode) => mode.name === "ct") || null
9+
);
10+
11+
const toggleModes = $state({
12+
clickThrough: false
13+
});
14+
15+
export function initializeBindingModesObserver() {
16+
$effect(() => {
17+
/* The click through binding mode needs to be configured to be toggled on and off
18+
* in the GlazeWM config.yaml file, and we just listen for its activation here as
19+
* a single toggle.
20+
* For example (config.yaml):
21+
*
22+
* # Sends a signal to Zebar via the binding mode
23+
* commands: ['wm-enable-binding-mode --name ct', "wm-disable-binding-mode --name ct"]
24+
* bindings: ['alt+shift+c']
25+
*
26+
*
27+
* The reason we do it this way is that GlazeWM binding modes do not inherit the
28+
* default keybindings, so in order to toggle our own custom mode while keeping all the keybindings,
29+
* we capture the activation signal by toggling the binding mode on and off and
30+
* save the state (signaled by the flip-flop) in our own Svelte state.
31+
*
32+
* If you think of a better way to do this, please let me know!
33+
*/
34+
35+
// Avoid cycles by untracking the current toggle state
36+
const currentToggle = untrack(() => toggleModes.clickThrough);
37+
38+
if (clickThroughBindingMode) {
39+
toggleModes.clickThrough = !currentToggle;
40+
}
41+
});
42+
43+
$effect(() => {
44+
// Here we use our custom state derived from the binding mode flip-flops
45+
const window = currentWidget().tauriWindow;
46+
if (toggleModes.clickThrough) {
47+
window.setIgnoreCursorEvents(true);
48+
console.log("Set window to click-through");
49+
} else {
50+
window.setIgnoreCursorEvents(false);
51+
console.log("Unset window to click-through");
52+
}
53+
});
54+
55+
configLoaded.then(() => {
56+
toggleModes.clickThrough = config.clickThroughByDefault;
57+
});
58+
}
59+
60+
export { toggleModes };

src/lib/config.svelte.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ export interface Config {
7676
*/
7777
showFullDateByDefault: boolean;
7878

79+
/**
80+
* Enable click-through by default.
81+
*/
82+
clickThroughByDefault: boolean;
83+
7984
// Individual section toggles
8085

8186
showHeartButton: boolean;

src/routes/+page.svelte

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import { Effect } from "@tauri-apps/api/window";
66
77
import { initializeAutotiler } from "$lib/autotiler.svelte";
8+
import { initializeBindingModesObserver } from "$lib/binding_modes.svelte";
89
import { config, configLoaded } from "$lib/config.svelte";
910
import { initProviders, providers } from "$lib/providers.svelte";
1011
import { isOnPrimaryMonitor } from "$lib/utils/glaze_wm_utils.svelte";
@@ -16,6 +17,7 @@
1617
1718
let glazewm = $derived(providers.glazewm);
1819
initializeAutotiler();
20+
initializeBindingModesObserver();
1921
2022
onMount(() => {
2123
initProviders();

static/config.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
},
2323
"backgroundEffect": "acrylic",
2424
"enableAutoTiling": true,
25+
"clickThroughByDefault": false,
2526
"showFullDateByDefault": false,
2627
"showHeartButton": true,
2728
"showCpuSection": true,

static/schema.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,10 @@
7777
"$ref": "#/definitions/BackgroundEffect",
7878
"description": "The background effect to use for the widget.\n\nNOTE: In order to use anything other than inherit, you must recompile zebar with an extra permission. More details in the README.\n\n`inherit`- Don't change the effect, and use the one defined in zpack.json (probably transparent).\n`acrylic`- Use an acrylic background effect. Windows 10, 11.\n`blur`- Use a blur background effect. Windows 10, 11.\n`mica`- Use a mica background effect. Windows 11 only."
7979
},
80+
"clickThroughByDefault": {
81+
"description": "Enable click-through by default.",
82+
"type": "boolean"
83+
},
8084
"direction": {
8185
"$ref": "#/definitions/AttachmentDirection",
8286
"description": "The visual direction of the widget.\n\n`top`- The top of the widget has inverted corner radius, and the bottom has normal corner radius.\n\n`bottom`- The bottom of the widget has inverted corner radius, and the top has normal corner radius.\n\n`floating`- All corners of the widget have normal corner radius."

0 commit comments

Comments
 (0)