diff options
-rwxr-xr-x | contrib/autoname-workspaces.py | 124 | ||||
-rwxr-xr-x | contrib/grimshot | 168 | ||||
-rw-r--r-- | contrib/grimshot.1 | 109 | ||||
-rw-r--r-- | contrib/grimshot.1.scd | 80 | ||||
-rwxr-xr-x | contrib/inactive-windows-transparency.py | 69 |
5 files changed, 0 insertions, 550 deletions
diff --git a/contrib/autoname-workspaces.py b/contrib/autoname-workspaces.py deleted file mode 100755 index 3ec39928..00000000 --- a/contrib/autoname-workspaces.py +++ /dev/null | |||
@@ -1,124 +0,0 @@ | |||
1 | #!/usr/bin/python | ||
2 | |||
3 | # This script requires i3ipc-python package (install it from a system package manager | ||
4 | # or pip). | ||
5 | # It adds icons to the workspace name for each open window. | ||
6 | # Set your keybindings like this: set $workspace1 workspace number 1 | ||
7 | # Add your icons to WINDOW_ICONS. | ||
8 | # Based on https://github.com/maximbaz/dotfiles/blob/master/bin/i3-autoname-workspaces | ||
9 | |||
10 | import argparse | ||
11 | import i3ipc | ||
12 | import logging | ||
13 | import re | ||
14 | import signal | ||
15 | import sys | ||
16 | |||
17 | WINDOW_ICONS = { | ||
18 | "firefox": "", | ||
19 | } | ||
20 | |||
21 | DEFAULT_ICON = "" | ||
22 | |||
23 | |||
24 | def icon_for_window(window): | ||
25 | name = None | ||
26 | if window.app_id is not None and len(window.app_id) > 0: | ||
27 | name = window.app_id.lower() | ||
28 | elif window.window_class is not None and len(window.window_class) > 0: | ||
29 | name = window.window_class.lower() | ||
30 | |||
31 | if name in WINDOW_ICONS: | ||
32 | return WINDOW_ICONS[name] | ||
33 | |||
34 | logging.info("No icon available for window with name: %s" % str(name)) | ||
35 | return DEFAULT_ICON | ||
36 | |||
37 | def rename_workspaces(ipc): | ||
38 | for workspace in ipc.get_tree().workspaces(): | ||
39 | name_parts = parse_workspace_name(workspace.name) | ||
40 | icon_tuple = () | ||
41 | for w in workspace: | ||
42 | if w.app_id is not None or w.window_class is not None: | ||
43 | icon = icon_for_window(w) | ||
44 | if not ARGUMENTS.duplicates and icon in icon_tuple: | ||
45 | continue | ||
46 | icon_tuple += (icon,) | ||
47 | name_parts["icons"] = " ".join(icon_tuple) + " " | ||
48 | new_name = construct_workspace_name(name_parts) | ||
49 | ipc.command('rename workspace "%s" to "%s"' % (workspace.name, new_name)) | ||
50 | |||
51 | |||
52 | def undo_window_renaming(ipc): | ||
53 | for workspace in ipc.get_tree().workspaces(): | ||
54 | name_parts = parse_workspace_name(workspace.name) | ||
55 | name_parts["icons"] = None | ||
56 | new_name = construct_workspace_name(name_parts) | ||
57 | ipc.command('rename workspace "%s" to "%s"' % (workspace.name, new_name)) | ||
58 | ipc.main_quit() | ||
59 | sys.exit(0) | ||
60 | |||
61 | |||
62 | def parse_workspace_name(name): | ||
63 | return re.match( | ||
64 | "(?P<num>[0-9]+):?(?P<shortname>\w+)? ?(?P<icons>.+)?", name | ||
65 | ).groupdict() | ||
66 | |||
67 | |||
68 | def construct_workspace_name(parts): | ||
69 | new_name = str(parts["num"]) | ||
70 | if parts["shortname"] or parts["icons"]: | ||
71 | new_name += ":" | ||
72 | |||
73 | if parts["shortname"]: | ||
74 | new_name += parts["shortname"] | ||
75 | |||
76 | if parts["icons"]: | ||
77 | new_name += " " + parts["icons"] | ||
78 | |||
79 | return new_name | ||
80 | |||
81 | |||
82 | if __name__ == "__main__": | ||
83 | parser = argparse.ArgumentParser( | ||
84 | description="This script automatically changes the workspace name in sway depending on your open applications." | ||
85 | ) | ||
86 | parser.add_argument( | ||
87 | "--duplicates", | ||
88 | "-d", | ||
89 | action="store_true", | ||
90 | help="Set it when you want an icon for each instance of the same application per workspace.", | ||
91 | ) | ||
92 | parser.add_argument( | ||
93 | "--logfile", | ||
94 | "-l", | ||
95 | type=str, | ||
96 | default="/tmp/sway-autoname-workspaces.log", | ||
97 | help="Path for the logfile.", | ||
98 | ) | ||
99 | args = parser.parse_args() | ||
100 | global ARGUMENTS | ||
101 | ARGUMENTS = args | ||
102 | |||
103 | logging.basicConfig( | ||
104 | level=logging.INFO, | ||
105 | filename=ARGUMENTS.logfile, | ||
106 | filemode="w", | ||
107 | format="%(message)s", | ||
108 | ) | ||
109 | |||
110 | ipc = i3ipc.Connection() | ||
111 | |||
112 | for sig in [signal.SIGINT, signal.SIGTERM]: | ||
113 | signal.signal(sig, lambda signal, frame: undo_window_renaming(ipc)) | ||
114 | |||
115 | def window_event_handler(ipc, e): | ||
116 | if e.change in ["new", "close", "move"]: | ||
117 | rename_workspaces(ipc) | ||
118 | |||
119 | ipc.on("window", window_event_handler) | ||
120 | |||
121 | rename_workspaces(ipc) | ||
122 | |||
123 | ipc.main() | ||
124 | |||
diff --git a/contrib/grimshot b/contrib/grimshot deleted file mode 100755 index 1ec19def..00000000 --- a/contrib/grimshot +++ /dev/null | |||
@@ -1,168 +0,0 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | ## Grimshot: a helper for screenshots within sway | ||
4 | ## Requirements: | ||
5 | ## - `grim`: screenshot utility for wayland | ||
6 | ## - `slurp`: to select an area | ||
7 | ## - `swaymsg`: to read properties of current window | ||
8 | ## - `wl-copy`: clipboard utility | ||
9 | ## - `jq`: json utility to parse swaymsg output | ||
10 | ## - `notify-send`: to show notifications | ||
11 | ## Those are needed to be installed, if unsure, run `grimshot check` | ||
12 | ## | ||
13 | ## See `man 1 grimshot` or `grimshot usage` for further details. | ||
14 | |||
15 | getTargetDirectory() { | ||
16 | test -f "${XDG_CONFIG_HOME:-$HOME/.config}/user-dirs.dirs" && \ | ||
17 | . "${XDG_CONFIG_HOME:-$HOME/.config}/user-dirs.dirs" | ||
18 | |||
19 | echo "${XDG_SCREENSHOTS_DIR:-${XDG_PICTURES_DIR:-$HOME}}" | ||
20 | } | ||
21 | |||
22 | NOTIFY=no | ||
23 | CURSOR= | ||
24 | |||
25 | while [ $# -gt 0 ]; do | ||
26 | key="$1" | ||
27 | |||
28 | case $key in | ||
29 | -n|--notify) | ||
30 | NOTIFY=yes | ||
31 | shift # past argument | ||
32 | ;; | ||
33 | -c|--cursor) | ||
34 | CURSOR=yes | ||
35 | shift # past argument | ||
36 | ;; | ||
37 | *) # unknown option | ||
38 | break # done with parsing --flags | ||
39 | ;; | ||
40 | esac | ||
41 | done | ||
42 | |||
43 | ACTION=${1:-usage} | ||
44 | SUBJECT=${2:-screen} | ||
45 | FILE=${3:-$(getTargetDirectory)/$(date -Ins).png} | ||
46 | |||
47 | if [ "$ACTION" != "save" ] && [ "$ACTION" != "copy" ] && [ "$ACTION" != "check" ]; then | ||
48 | echo "Usage:" | ||
49 | echo " grimshot [--notify] [--cursor] (copy|save) [active|screen|output|area|window] [FILE|-]" | ||
50 | echo " grimshot check" | ||
51 | echo " grimshot usage" | ||
52 | echo "" | ||
53 | echo "Commands:" | ||
54 | echo " copy: Copy the screenshot data into the clipboard." | ||
55 | echo " save: Save the screenshot to a regular file or '-' to pipe to STDOUT." | ||
56 | echo " check: Verify if required tools are installed and exit." | ||
57 | echo " usage: Show this message and exit." | ||
58 | echo "" | ||
59 | echo "Targets:" | ||
60 | echo " active: Currently active window." | ||
61 | echo " screen: All visible outputs." | ||
62 | echo " output: Currently active output." | ||
63 | echo " area: Manually select a region." | ||
64 | echo " window: Manually select a window." | ||
65 | exit | ||
66 | fi | ||
67 | |||
68 | notify() { | ||
69 | notify-send -t 3000 -a grimshot "$@" | ||
70 | } | ||
71 | notifyOk() { | ||
72 | [ "$NOTIFY" = "no" ] && return | ||
73 | |||
74 | TITLE=${2:-"Screenshot"} | ||
75 | MESSAGE=${1:-"OK"} | ||
76 | notify "$TITLE" "$MESSAGE" | ||
77 | } | ||
78 | notifyError() { | ||
79 | if [ $NOTIFY = "yes" ]; then | ||
80 | TITLE=${2:-"Screenshot"} | ||
81 | MESSAGE=${1:-"Error taking screenshot with grim"} | ||
82 | notify -u critical "$TITLE" "$MESSAGE" | ||
83 | else | ||
84 | echo "$1" | ||
85 | fi | ||
86 | } | ||
87 | |||
88 | die() { | ||
89 | MSG=${1:-Bye} | ||
90 | notifyError "Error: $MSG" | ||
91 | exit 2 | ||
92 | } | ||
93 | |||
94 | check() { | ||
95 | COMMAND=$1 | ||
96 | if command -v "$COMMAND" > /dev/null 2>&1; then | ||
97 | RESULT="OK" | ||
98 | else | ||
99 | RESULT="NOT FOUND" | ||
100 | fi | ||
101 | echo " $COMMAND: $RESULT" | ||
102 | } | ||
103 | |||
104 | takeScreenshot() { | ||
105 | FILE=$1 | ||
106 | GEOM=$2 | ||
107 | OUTPUT=$3 | ||
108 | if [ -n "$OUTPUT" ]; then | ||
109 | grim ${CURSOR:+-c} -o "$OUTPUT" "$FILE" || die "Unable to invoke grim" | ||
110 | elif [ -z "$GEOM" ]; then | ||
111 | grim ${CURSOR:+-c} "$FILE" || die "Unable to invoke grim" | ||
112 | else | ||
113 | grim ${CURSOR:+-c} -g "$GEOM" "$FILE" || die "Unable to invoke grim" | ||
114 | fi | ||
115 | } | ||
116 | |||
117 | if [ "$ACTION" = "check" ] ; then | ||
118 | echo "Checking if required tools are installed. If something is missing, install it to your system and make it available in PATH..." | ||
119 | check grim | ||
120 | check slurp | ||
121 | check swaymsg | ||
122 | check wl-copy | ||
123 | check jq | ||
124 | check notify-send | ||
125 | exit | ||
126 | elif [ "$SUBJECT" = "area" ] ; then | ||
127 | GEOM=$(slurp -d) | ||
128 | # Check if user exited slurp without selecting the area | ||
129 | if [ -z "$GEOM" ]; then | ||
130 | exit 1 | ||
131 | fi | ||
132 | WHAT="Area" | ||
133 | elif [ "$SUBJECT" = "active" ] ; then | ||
134 | FOCUSED=$(swaymsg -t get_tree | jq -r 'recurse(.nodes[]?, .floating_nodes[]?) | select(.focused)') | ||
135 | GEOM=$(echo "$FOCUSED" | jq -r '.rect | "\(.x),\(.y) \(.width)x\(.height)"') | ||
136 | APP_ID=$(echo "$FOCUSED" | jq -r '.app_id') | ||
137 | WHAT="$APP_ID window" | ||
138 | elif [ "$SUBJECT" = "screen" ] ; then | ||
139 | GEOM="" | ||
140 | WHAT="Screen" | ||
141 | elif [ "$SUBJECT" = "output" ] ; then | ||
142 | GEOM="" | ||
143 | OUTPUT=$(swaymsg -t get_outputs | jq -r '.[] | select(.focused)' | jq -r '.name') | ||
144 | WHAT="$OUTPUT" | ||
145 | elif [ "$SUBJECT" = "window" ] ; then | ||
146 | GEOM=$(swaymsg -t get_tree | jq -r '.. | select(.pid? and .visible?) | .rect | "\(.x),\(.y) \(.width)x\(.height)"' | slurp) | ||
147 | # Check if user exited slurp without selecting the area | ||
148 | if [ -z "$GEOM" ]; then | ||
149 | exit 1 | ||
150 | fi | ||
151 | WHAT="Window" | ||
152 | else | ||
153 | die "Unknown subject to take a screen shot from" "$SUBJECT" | ||
154 | fi | ||
155 | |||
156 | if [ "$ACTION" = "copy" ] ; then | ||
157 | takeScreenshot - "$GEOM" "$OUTPUT" | wl-copy --type image/png || die "Clipboard error" | ||
158 | notifyOk "$WHAT copied to buffer" | ||
159 | else | ||
160 | if takeScreenshot "$FILE" "$GEOM" "$OUTPUT"; then | ||
161 | TITLE="Screenshot of $SUBJECT" | ||
162 | MESSAGE=$(basename "$FILE") | ||
163 | notifyOk "$MESSAGE" "$TITLE" | ||
164 | echo "$FILE" | ||
165 | else | ||
166 | notifyError "Error taking screenshot with grim" | ||
167 | fi | ||
168 | fi | ||
diff --git a/contrib/grimshot.1 b/contrib/grimshot.1 deleted file mode 100644 index 2c4c6a95..00000000 --- a/contrib/grimshot.1 +++ /dev/null | |||
@@ -1,109 +0,0 @@ | |||
1 | .\" Generated by scdoc 1.11.2 | ||
2 | .\" Complete documentation for this program is not available as a GNU info page | ||
3 | .ie \n(.g .ds Aq \(aq | ||
4 | .el .ds Aq ' | ||
5 | .nh | ||
6 | .ad l | ||
7 | .\" Begin generated content: | ||
8 | .TH "grimshot" "1" "2022-03-31" | ||
9 | .P | ||
10 | .SH NAME | ||
11 | .P | ||
12 | grimshot - a helper for screenshots within sway | ||
13 | .P | ||
14 | .SH SYNOPSIS | ||
15 | .P | ||
16 | \fBgrimshot\fR [--notify] [--cursor] (copy|save) [TARGET] [FILE] | ||
17 | .br | ||
18 | \fBgrimshot\fR check | ||
19 | .br | ||
20 | \fBgrimshot\fR usage | ||
21 | .P | ||
22 | .SH OPTIONS | ||
23 | .P | ||
24 | \fB--notify\fR | ||
25 | .RS 4 | ||
26 | Show notifications to the user that a screenshot has been taken.\& | ||
27 | .P | ||
28 | .RE | ||
29 | \fB--cursor\fR | ||
30 | .RS 4 | ||
31 | Include cursors in the screenshot.\& | ||
32 | .P | ||
33 | .RE | ||
34 | \fBsave\fR | ||
35 | .RS 4 | ||
36 | Save the screenshot into a regular file.\& Grimshot will write images | ||
37 | files to \fBXDG_SCREENSHOTS_DIR\fR if this is set (or defined | ||
38 | in \fBuser-dirs.\&dir\fR), or otherwise fall back to \fBXDG_PICTURES_DIR\fR.\& | ||
39 | Set FILE to '\&-'\& to pipe the output to STDOUT.\& | ||
40 | .P | ||
41 | .RE | ||
42 | \fBcopy\fR | ||
43 | .RS 4 | ||
44 | Copy the screenshot data (as image/png) into the clipboard.\& | ||
45 | .P | ||
46 | .RE | ||
47 | .SH DESCRIPTION | ||
48 | .P | ||
49 | Grimshot is an easy-to-use screenshot utility for sway.\& It provides a | ||
50 | convenient interface over grim, slurp and jq, and supports storing the | ||
51 | screenshot either directly to the clipboard using wl-copy or to a file.\& | ||
52 | .P | ||
53 | .SH EXAMPLES | ||
54 | .P | ||
55 | An example usage pattern is to add these bindings to your sway config: | ||
56 | .P | ||
57 | .nf | ||
58 | .RS 4 | ||
59 | # Screenshots: | ||
60 | # Super+P: Current window | ||
61 | # Super+Shift+p: Select area | ||
62 | # Super+Alt+p Current output | ||
63 | # Super+Ctrl+p Select a window | ||
64 | |||
65 | bindsym Mod4+p exec grimshot save active | ||
66 | bindsym Mod4+Shift+p exec grimshot save area | ||
67 | bindsym Mod4+Mod1+p exec grimshot save output | ||
68 | bindsym Mod4+Ctrl+p exec grimshot save window | ||
69 | .fi | ||
70 | .RE | ||
71 | .P | ||
72 | .SH TARGETS | ||
73 | .P | ||
74 | grimshot can capture the following named targets: | ||
75 | .P | ||
76 | \fIactive\fR | ||
77 | .RS 4 | ||
78 | Captures the currently active window.\& | ||
79 | .P | ||
80 | .RE | ||
81 | \fIscreen\fR | ||
82 | .RS 4 | ||
83 | Captures the entire screen.\& This includes all visible outputs.\& | ||
84 | .P | ||
85 | .RE | ||
86 | \fIarea\fR | ||
87 | .RS 4 | ||
88 | Allows manually selecting a rectangular region, and captures that.\& | ||
89 | .P | ||
90 | .RE | ||
91 | \fIwindow\fR | ||
92 | .RS 4 | ||
93 | Allows manually selecting a single window (by clicking on it), and | ||
94 | captures it.\& | ||
95 | .P | ||
96 | .RE | ||
97 | \fIoutput\fR | ||
98 | .RS 4 | ||
99 | Captures the currently active output.\& | ||
100 | .P | ||
101 | .RE | ||
102 | .SH OUTPUT | ||
103 | .P | ||
104 | Grimshot will print the filename of the captured screenshot to stdout if called | ||
105 | with the \fIsave\fR subcommand.\& | ||
106 | .P | ||
107 | .SH SEE ALSO | ||
108 | .P | ||
109 | \fBgrim\fR(1) | ||
diff --git a/contrib/grimshot.1.scd b/contrib/grimshot.1.scd deleted file mode 100644 index e356f99d..00000000 --- a/contrib/grimshot.1.scd +++ /dev/null | |||
@@ -1,80 +0,0 @@ | |||
1 | grimshot(1) | ||
2 | |||
3 | # NAME | ||
4 | |||
5 | grimshot - a helper for screenshots within sway | ||
6 | |||
7 | # SYNOPSIS | ||
8 | |||
9 | *grimshot* [--notify] [--cursor] (copy|save) [TARGET] [FILE]++ | ||
10 | *grimshot* check++ | ||
11 | *grimshot* usage | ||
12 | |||
13 | # OPTIONS | ||
14 | |||
15 | *--notify* | ||
16 | Show notifications to the user that a screenshot has been taken. | ||
17 | |||
18 | *--cursor* | ||
19 | Include cursors in the screenshot. | ||
20 | |||
21 | *save* | ||
22 | Save the screenshot into a regular file. Grimshot will write image | ||
23 | files to *XDG_SCREENSHOTS_DIR* if this is set (or defined | ||
24 | in *user-dirs.dir*), or otherwise fall back to *XDG_PICTURES_DIR*. | ||
25 | Set FILE to '-' to pipe the output to STDOUT. | ||
26 | |||
27 | *copy* | ||
28 | Copy the screenshot data (as image/png) into the clipboard. | ||
29 | |||
30 | # DESCRIPTION | ||
31 | |||
32 | Grimshot is an easy-to-use screenshot utility for sway. It provides a | ||
33 | convenient interface over grim, slurp and jq, and supports storing the | ||
34 | screenshot either directly to the clipboard using wl-copy or to a file. | ||
35 | |||
36 | # EXAMPLES | ||
37 | |||
38 | An example usage pattern is to add these bindings to your sway config: | ||
39 | |||
40 | ``` | ||
41 | # Screenshots: | ||
42 | # Super+P: Current window | ||
43 | # Super+Shift+p: Select area | ||
44 | # Super+Alt+p Current output | ||
45 | # Super+Ctrl+p Select a window | ||
46 | |||
47 | bindsym Mod4+p exec grimshot save active | ||
48 | bindsym Mod4+Shift+p exec grimshot save area | ||
49 | bindsym Mod4+Mod1+p exec grimshot save output | ||
50 | bindsym Mod4+Ctrl+p exec grimshot save window | ||
51 | ``` | ||
52 | |||
53 | # TARGETS | ||
54 | |||
55 | grimshot can capture the following named targets: | ||
56 | |||
57 | _active_ | ||
58 | Captures the currently active window. | ||
59 | |||
60 | _screen_ | ||
61 | Captures the entire screen. This includes all visible outputs. | ||
62 | |||
63 | _area_ | ||
64 | Allows manually selecting a rectangular region, and captures that. | ||
65 | |||
66 | _window_ | ||
67 | Allows manually selecting a single window (by clicking on it), and | ||
68 | captures it. | ||
69 | |||
70 | _output_ | ||
71 | Captures the currently active output. | ||
72 | |||
73 | # OUTPUT | ||
74 | |||
75 | Grimshot will print the filename of the captured screenshot to stdout if called | ||
76 | with the _save_ subcommand. | ||
77 | |||
78 | # SEE ALSO | ||
79 | |||
80 | *grim*(1) | ||
diff --git a/contrib/inactive-windows-transparency.py b/contrib/inactive-windows-transparency.py deleted file mode 100755 index b81134dd..00000000 --- a/contrib/inactive-windows-transparency.py +++ /dev/null | |||
@@ -1,69 +0,0 @@ | |||
1 | #!/usr/bin/python | ||
2 | |||
3 | # This script requires i3ipc-python package (install it from a system package manager | ||
4 | # or pip). | ||
5 | # It makes inactive windows transparent. Use `transparency_val` variable to control | ||
6 | # transparency strength in range of 0…1 or use the command line argument -o. | ||
7 | |||
8 | import argparse | ||
9 | import i3ipc | ||
10 | import signal | ||
11 | import sys | ||
12 | from functools import partial | ||
13 | |||
14 | def on_window_focus(inactive_opacity, ipc, event): | ||
15 | global prev_focused | ||
16 | global prev_workspace | ||
17 | |||
18 | focused_workspace = ipc.get_tree().find_focused() | ||
19 | |||
20 | if focused_workspace == None: | ||
21 | return | ||
22 | |||
23 | focused = event.container | ||
24 | workspace = focused_workspace.workspace().num | ||
25 | |||
26 | if focused.id != prev_focused.id: # https://github.com/swaywm/sway/issues/2859 | ||
27 | focused.command("opacity 1") | ||
28 | if workspace == prev_workspace: | ||
29 | prev_focused.command("opacity " + inactive_opacity) | ||
30 | prev_focused = focused | ||
31 | prev_workspace = workspace | ||
32 | |||
33 | |||
34 | def remove_opacity(ipc): | ||
35 | for workspace in ipc.get_tree().workspaces(): | ||
36 | for w in workspace: | ||
37 | w.command("opacity 1") | ||
38 | ipc.main_quit() | ||
39 | sys.exit(0) | ||
40 | |||
41 | |||
42 | if __name__ == "__main__": | ||
43 | transparency_val = "0.80" | ||
44 | |||
45 | parser = argparse.ArgumentParser( | ||
46 | description="This script allows you to set the transparency of unfocused windows in sway." | ||
47 | ) | ||
48 | parser.add_argument( | ||
49 | "--opacity", | ||
50 | "-o", | ||
51 | type=str, | ||
52 | default=transparency_val, | ||
53 | help="set opacity value in range 0...1", | ||
54 | ) | ||
55 | args = parser.parse_args() | ||
56 | |||
57 | ipc = i3ipc.Connection() | ||
58 | prev_focused = None | ||
59 | prev_workspace = ipc.get_tree().find_focused().workspace().num | ||
60 | |||
61 | for window in ipc.get_tree(): | ||
62 | if window.focused: | ||
63 | prev_focused = window | ||
64 | else: | ||
65 | window.command("opacity " + args.opacity) | ||
66 | for sig in [signal.SIGINT, signal.SIGTERM]: | ||
67 | signal.signal(sig, lambda signal, frame: remove_opacity(ipc)) | ||
68 | ipc.on("window::focus", partial(on_window_focus, args.opacity)) | ||
69 | ipc.main() \ No newline at end of file | ||